📋 Prerequisites
🎯 Affected Service(s)
Not Sure
🚦 Impact/Severity
No impact (Default)
🐛 Bug Description
For type: BYO agents, the kagent controller continuously overrides HPA-managed replica counts, causing a fight loop between the HPA and the controller. The Deployment replicas are reset to 1 on every reconcile cycle even when replicas is intentionally omitted from the Agent CR.
🔄 Steps To Reproduce
Deploy a type: BYO Agent without a replicas field in spec.byo.deployment
Attach a Kubernetes HPA targeting the kagent-created Deployment with minReplicas: 2
Observe kubectl describe deployment -n kagent events — the controller repeatedly scales down what the HPA scales up
🤔 Expected Behavior
When replicas is not set in spec.byo.deployment, the controller should leave the Deployment's replica count untouched, allowing an HPA (or KEDA) to own replica management — consistent with the HPA-awareness comment already present in mutate.go.
📱 Actual Behavior
The controller resets the Deployment to 1 replica on every reconcile, overriding any HPA scaling. Observed in Deployment events:
Scaled up replica set xxxx-agent-v1-xxx from 1 to 2 ← HPA
Scaled down replica set xxxx-agent-v1-xxx from 2 to 1 ← controller
Scaled up replica set xxxx-agent-v1-xxx from 1 to 2 ← HPA
Scaled down replica set xxxx-agent-v1-xxx from 2 to 1 ← controller
(repeating every ~2 minutes)
💻 Environment
kagent version: v1alpha2
Agent type: BYO
Kubernetes: GKE
🔧 CLI Bug Report
No response
🔍 Additional Context
Root cause
go/core/internal/controller/translator/agent/deployments.go in resolveByoDeployment() always fills in a default of 1 when spec.Replicas is nil:
replicas := spec.Replicas
if replicas == nil {
replicas = new(int32(1)) // ← forces replicas=1 into desired Deployment
}
This means desired.Spec.Replicas is never nil for BYO agents. As a result, the guard in mutate.go always fires and overrides:
if desired.Spec.Replicas != nil {
// only set replicas if explicitly specified, so not to override HPA settings
existing.Spec.Replicas = desired.Spec.Replicas // always triggers for BYO
}
The HPA-awareness in mutate.go works correctly in isolation but is bypassed for BYO agents because deployments.go prevents Replicas from ever being nil.
Note: This does not affect type: Declarative agents where this default-filling logic is absent.
Suggested fix
Remove the default fallback in deployments.go so that a nil spec.Replicas propagates through to the desired Deployment spec, allowing mutate.go's existing HPA-awareness check to function as intended:
// Before
replicas := spec.Replicas
if replicas == nil {
replicas = new(int32(1))
}
// After
replicas := spec.Replicas
// Leave nil if unset — mutate.go will preserve existing (HPA-managed) replicas
📋 Logs
📷 Screenshots
No response
🙋 Are you willing to contribute?
📋 Prerequisites
🎯 Affected Service(s)
Not Sure
🚦 Impact/Severity
No impact (Default)
🐛 Bug Description
For type: BYO agents, the kagent controller continuously overrides HPA-managed replica counts, causing a fight loop between the HPA and the controller. The Deployment replicas are reset to 1 on every reconcile cycle even when replicas is intentionally omitted from the Agent CR.
🔄 Steps To Reproduce
Deploy a type: BYO Agent without a replicas field in spec.byo.deployment
Attach a Kubernetes HPA targeting the kagent-created Deployment with minReplicas: 2
Observe kubectl describe deployment -n kagent events — the controller repeatedly scales down what the HPA scales up
🤔 Expected Behavior
When replicas is not set in spec.byo.deployment, the controller should leave the Deployment's replica count untouched, allowing an HPA (or KEDA) to own replica management — consistent with the HPA-awareness comment already present in mutate.go.
📱 Actual Behavior
The controller resets the Deployment to 1 replica on every reconcile, overriding any HPA scaling. Observed in Deployment events:
Scaled up replica set xxxx-agent-v1-xxx from 1 to 2 ← HPA
Scaled down replica set xxxx-agent-v1-xxx from 2 to 1 ← controller
Scaled up replica set xxxx-agent-v1-xxx from 1 to 2 ← HPA
Scaled down replica set xxxx-agent-v1-xxx from 2 to 1 ← controller
(repeating every ~2 minutes)
💻 Environment
kagent version: v1alpha2
Agent type: BYO
Kubernetes: GKE
🔧 CLI Bug Report
No response
🔍 Additional Context
Root cause
go/core/internal/controller/translator/agent/deployments.go in resolveByoDeployment() always fills in a default of 1 when spec.Replicas is nil:
replicas := spec.Replicas
if replicas == nil {
replicas = new(int32(1)) // ← forces replicas=1 into desired Deployment
}
This means desired.Spec.Replicas is never nil for BYO agents. As a result, the guard in mutate.go always fires and overrides:
if desired.Spec.Replicas != nil {
// only set replicas if explicitly specified, so not to override HPA settings
existing.Spec.Replicas = desired.Spec.Replicas // always triggers for BYO
}
The HPA-awareness in mutate.go works correctly in isolation but is bypassed for BYO agents because deployments.go prevents Replicas from ever being nil.
Note: This does not affect type: Declarative agents where this default-filling logic is absent.
Suggested fix
Remove the default fallback in deployments.go so that a nil spec.Replicas propagates through to the desired Deployment spec, allowing mutate.go's existing HPA-awareness check to function as intended:
// Before
replicas := spec.Replicas
if replicas == nil {
replicas = new(int32(1))
}
// After
replicas := spec.Replicas
// Leave nil if unset — mutate.go will preserve existing (HPA-managed) replicas
📋 Logs
📷 Screenshots
No response
🙋 Are you willing to contribute?