KEDA Troubleshooting: ScaledObject Ready, Auth, and Scaling Delay Fixes

Updated on Sep 20, 2026
Mila H
9 MINS READ
Table of Contents
KEDA ScaledObject Troubleshooting

KEDA scales pods on real signals like queue length, Kafka lag, or Prometheus metrics, not just CPU and memory. This KEDA ScaledObject troubleshooting guide fixes the common failures on a cluster that already runs KEDA. If KEDA isn't running yet, follow our KEDA on K3s autoscaling tutorial

Confirm KEDA Itself Is Healthy

Before changing any ScaledObject, you must check that KEDA itself is healthy:

Bash
kubectl get pods -n keda

You should see keda-operator, keda-operator-metrics-apiserver, and keda-admission-webhooks deployments are running. If any pod is not Running, check its logs first:

Bash
kubectl logs -n keda deploy/keda-operator

From here, we assume this check passes, and your KEDA pods are healthy and running.

Set Up a Test Project to Debug

To try the fixes yourself, you can create a simple test workload, credential, and ScaledObject. Skip this if you already have your own set up. Create demo-deployment.yaml:

Bash
cat <<EOF > demo-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: demo-app  namespace: defaultspec:  replicas: 1  selector:    matchLabels:      app: demo-app  template:    metadata:      labels:        app: demo-app    spec:      containers:        - name: demo-app          image: nginx:1.27          resources:            requests:              cpu: 50m              memory: 64Mi            limits:              cpu: 200m              memory: 128Mi          ports:            - containerPort: 80EOF

Apply the test deployment file with the command below:

Bash
kubectl apply -f demo-deployment.yaml

Then, create demo-secret.yaml for the credentials your trigger will use:

Bash
cat <<EOF > demo-secret.yamlapiVersion: v1kind: Secretmetadata:  name: demo-credentials  namespace: defaulttype: OpaquestringData:  username: "demo-user"  password: "demo-password"EOF

Apply it the same way:

Bash
kubectl apply -f demo-secret.yaml

Use the command below to create demo-triggerauth.yaml:

Bash
cat <<EOF > demo-triggerauth.yamlapiVersion: keda.sh/v1alpha1kind: TriggerAuthenticationmetadata:  name: demo-trigger-auth  namespace: defaultspec:  secretTargetRef:    - parameter: username      name: demo-credentials      key: username    - parameter: password      name: demo-credentials      key: passwordEOF

Apply it:

Bash
kubectl apply -f demo-triggerauth.yaml

If your credentials come from AWS, Azure, or GCP, skip the Secret entirely and use pod identity instead:

Bash
cat <<EOF > aws-triggerauth.yamlapiVersion: keda.sh/v1alpha1kind: TriggerAuthenticationmetadata:  name: aws-trigger-auth  namespace: defaultspec:  podIdentity:    provider: awsEOF

Note: the older aws-eks provider value still works but is deprecated and is being removed. Use aws for AWS, azure-workload for Azure, and gcp for Google Cloud.

Finally, create demo-scaledobject.yaml using the Prometheus scaler, because it is the most flexible one for custom app metrics:

Bash
cat <<EOF > demo-scaledobject.yamlapiVersion: keda.sh/v1alpha1kind: ScaledObjectmetadata:  name: demo-scaledobject  namespace: defaultspec:  scaleTargetRef:    name: demo-app  pollingInterval: 15  cooldownPeriod: 60  minReplicaCount: 0  maxReplicaCount: 10  triggers:    - type: prometheus      metadata:        serverAddress: http://prometheus.monitoring.svc:9090        metricName: http_requests_per_second        query: sum(rate(http_requests_total{app="demo-app"}[2m]))        threshold: "10"      authenticationRef:        name: demo-trigger-authEOF

Apply and check the results with the commands below:

Bash
kubectl apply -f demo-scaledobject.yamlkubectl get scaledobject demo-scaledobject

Expected output looks like this:

Bash
NAME                 SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   READY   ACTIVE   FALLBACK   PAUSED   AGEdemo-scaledobject    apps/v1.Deployment   demo-app          0     10    True    False    False      False    20s

READY: True means KEDA accepted your config and made the HPA. ACTIVE: False means no trigger has crossed its threshold yet, which is normal and not an error. If your output looks different, go to the checklist below.

KEDA ScaledObject Troubleshooting: The Full Checklist

This section is the core of this KEDA ScaledObject troubleshooting guide. Go through these checks in order; each one rules out a different layer of the problem.

1. ScaledObject Stuck at Ready: False

First, you must run the command below:

Bash
kubectl describe scaledobject demo-scaledobject

Look at the Status.Conditions block. A Ready: False condition means one of these:

  • Duplicate HPA name. KEDA wants to create keda-hpa-demo-scaledobject, but an HPA already exists with that name or targets the same Deployment. Run kubectl get hpa -A -o wide and check for a second HPA on the same scaleTargetRef.
  • RBAC problem. KEDA's service account can't create HPAs or read your Secret. Check kubectl logs -n keda deploy/keda-operator for the word forbidden.
  • Invalid trigger metadata. A typo in a required field, like a missing serverAddress or misspelled queueName, fails validation before KEDA even tries to poll.
  • Admission webhook rejection. KEDA blocks a ScaledObject that breaks its own rules, such as minReplicaCount set higher than maxReplicaCount. You'll see the error when you run kubectl apply.

That's why kubectl describe should be your first move, not the operator logs. The condition message usually tells you exactly what's wrong.

2. TriggerAuthentication and Secret Errors

If the ScaledObject is Ready: True but the metric never updates, or the operator logs show authentication failed or unable to get credentials, check these in order:

Bash
kubectl get secret demo-credentials -n defaultkubectl get triggerauthentication demo-trigger-auth -n default -o yaml

Common mistakes include:

  • Wrong namespace. TriggerAuthentication must be in the same namespace as the ScaledObject. For credentials shared across namespaces, use ClusterTriggerAuthentication instead.

  • Wrong key name. The key in secretTargetRef doesn't match the Secret. Run kubectl get secret demo-credentials -o jsonpath='{.data}' to see the real key names.

  • Stale cached secret. If you rotated the secret, KEDA may still have the old value cached. Restart it: kubectl rollout restart deployment/keda-operator -n keda.

  • Missing pod identity annotation. For cloud identity, check that the Deployment's serviceAccountName has the right annotation linking it to your cloud IAM role.

3. Bad Queue URLs and Wrong Connection Strings

A wrong queueURL, bootstrapServers, or host usually won't fail Ready. It just fails quietly when KEDA tries to poll, so the ScaledObject stays stuck at minReplicaCount. KEDA reads no activity from a queue that doesn't exist, or the connection times out.

Confirm connectivity directly from inside the cluster:

Bash
kubectl run debug-pod --rm -it --image=busybox -- /bin/sh# inside the pod:nc -vz <queue-host> <port>

Also, check the operator logs for the connection error. It's much more specific than what the ScaledObject status shows:

Bash
kubectl logs -n keda deploy/keda-operator -f | grep -i "error\|scaler"

Errors like connection refused, no such host, or context deadline exceeded point at a wrong URL, a firewall rule, or a DNS issue, not a KEDA bug.

4. Inaccessible Prometheus Endpoints

For the Prometheus scaler, three things need to work: KEDA must be able to reach serverAddress, the query must be valid PromQL, and it must return a single number. Test the same query directly:

Bash
kubectl run debug-pod --rm -it --image=curlimages/curl -- \  curl "http://prometheus.monitoring.svc:9090/api/v1/query?query=sum(rate(http_requests_total%5B2m%5D))"

If this fails from inside the cluster, the Prometheus endpoint is unreachable. No ScaledObject tuning will fix that; you need to fix the network path first. If it succeeds but returns several results instead of one number, wrap your query in sum(). KEDA only accepts a single number and rejects anything else with an error.

5. Incorrect or Unexpected Metric Values

If KEDA is polling fine but the replica count still looks wrong, check the metric value KEDA is sending to the HPA directly, skipping your event source entirely:

Bash
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/s0-prometheus-demo-scaledobject" | jq .

If this returns a normal number, KEDA and the metrics pipeline are working fine. Any leftover scaling issue is an HPA or threshold tuning problem, not a metric problem. If the call fails, check that the metrics API is registered and healthy:

Bash
kubectl get apiservice v1beta1.external.metrics.k8s.io

This one command is the easiest way to separate a metric problem from a KEDA problem, which is the whole point of this KEDA ScaledObject troubleshooting guide.

Fix HPA Conflicts in KEDA Deployments

Kubernetes only allows one HPA per target. If your Deployment already has a manual HPA for CPU scaling and you add a ScaledObject on top, the two controllers fight over the replica count, or KEDA's HPA quietly fails to work.

Check for conflicts before applying any ScaledObject:

Bash
kubectl get hpa -Akubectl get scaledobject -A

Compare the scaleTargetRef on each. If a manual HPA already targets your Deployment, delete it before migrating to KEDA:

Bash
kubectl delete hpa <old-hpa-name> -n <namespace>

If you still need CPU-based scaling alongside your event trigger, don't run two separate HPAs. Add a cpu trigger inside the same ScaledObject instead; KEDA's single HPA will check both signals and use whichever asks for more replicas:

YAML
triggers:  - type: cpu    metricType: Utilization    metadata:      value: "70"  - type: prometheus    metadata:      serverAddress: http://prometheus.monitoring.svc:9090      metricName: http_requests_per_second      query: sum(rate(http_requests_total{app="demo-app"}[2m]))      threshold: "10"

KEDA Cooldown Period Mistakes

cooldownPeriod, default 300 seconds, only controls the wait before scaling down to zero. It doesn't slow down normal scale-down, like going from 5 replicas to 3. That's controlled by the HPA's behavior.scaleDown settings instead. 

If your workload switches rapidly between 0 and 1 replica, raise cooldownPeriod. If it switches between nonzero counts, like 4 and 5, that's an HPA stabilization issue instead. Fix it like this inside your demo-scaledobject.yaml:

YAML
spec:  advanced:    horizontalPodAutoscalerConfig:      behavior:        scaleDown:          stabilizationWindowSeconds: 300          policies:            - type: Percent              value: 25              periodSeconds: 60        scaleUp:          stabilizationWindowSeconds: 0          policies:            - type: Pods              value: 4              periodSeconds: 30

Fix KEDA Scale-to-Zero Issues

Scale-to-zero is special-cased inside KEDA, because the HPA API itself cannot express zero replicas. KEDA temporarily removes or pauses the HPA while at zero, then recreates it when a trigger activates. If scale-to-zero seems stuck, check these:

  • idleReplicaCount misuse. Only 0 reliably works here, due to a limit in the HPA controller. If you need "always at least 1 pod," use minReplicaCount: 1 instead.
  • Leftover pause annotation. Someone may have paused the object during a past issue and forgot to remove it:
Bash
kubectl get scaledobject demo-scaledobject -o jsonpath='{.metadata.annotations}'

To remove a stuck pause, you can use the following command:

Bash
kubectl annotate scaledobject demo-scaledobject autoscaling.keda.sh/paused-
  • First-event delay. After scaling to zero, the first new event has to wait for the next pollingInterval check before KEDA notices and scales up. For faster response, lower pollingInterval to 5–10 seconds.
  • Connection errors read as no activity. If the event source is unreachable, KEDA logs an error but usually keeps the last known scale instead of dropping to zero, unless you set a fallback. If a workload is stuck at zero when you expected it to hold its scale, the scaler is likely failing, not idle.

Kubernetes Scheduling Issues After KEDA Scales Up

Sometimes the ScaledObject and HPA are working perfectly, replicas increase, but new pods sit in Pending forever. This is a Kubernetes scheduling problem, completely separate from KEDA. Check these:

Bash
kubectl describe pod <pending-pod-name>

Check the Events section at the bottom for the real reason. It's usually one of these:

  • Not enough CPU or memory. No node has room. Add nodes or lower resources.requests on your Deployment.

  • Node restrictions block the pod. The node has a restriction your pod doesn't allow for.

  • PodDisruptionBudget or affinity rules blocking placement.

  • Image pull failures. A wrong image tag or missing registry credentials; it looks like a scaling issue but is really a pull error.

Conclusion

Most KEDA problems aren't really KEDA bugs. They come from the scaler can't reach the event source, the HPA can't resolve due to a conflict or bad math, or Kubernetes can't schedule the pods.

If scaling still looks off after this KEDA ScaledObject troubleshooting, the issue may be your infrastructure itself. Running KEDA on a dedicated server with fixed resources helps separate real scaling errors from capacity limits.