Skip to main content

Kubernetes · troubleshooting

Service has no endpoints

The Service exists and resolves, and nothing is behind it. Almost always the selector, the readiness of the pods, or the port — and which one it is takes two commands to establish.

Run this first

step 1 of 4
kubectl get endpoints <service>

Look for ENDPOINTS showing <none>

Confirms the symptom in one line and tells you immediately whether this is the problem you have. An empty list here is the whole diagnosis of where the fault is not.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Does `kubectl get pods -l <your selector>` return any pods at all?

Use the exact selector from the Service, not the one you meant to write.

Cause space

5 of 5 still possible

  • The selector does not match the pod labelsCommon
  • The pods match but none are ReadyCommon
  • targetPort does not match the container portCommon
  • The pods are in a different namespaceOccasional
  • There are no pods at allOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Check it with a tool

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    kubectl get endpoints <service>

    Confirms the symptom in one line and tells you immediately whether this is the problem you have. An empty list here is the whole diagnosis of where the fault is not.

    Look for ENDPOINTS showing <none>

  2. Step 2

    kubectl get svc <service> -o jsonpath='{.spec.selector}'; echo; kubectl get pods --show-labels

    Puts the selector next to the labels that exist, which resolves the most common cause by reading rather than guessing.

    Look for A key or value in the selector that no pod carries

  3. Step 3

    kubectl get pods -l app=<label> -o wide

    Separates 'no pods match' from 'pods match but are not Ready'. These look identical at the Service and need entirely different fixes.

    Look for READY 0/1 with STATUS Running, which points at the readiness probe

  4. Step 4

    kubectl describe svc <service>

    Shows the resolved ports and any events the Service itself recorded.

    Look for TargetPort, and an Endpoints line confirming what the control plane computed

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The selector does not match the pod labels

Common

The Service's selector and the pod template's labels differ — a typo, a renamed app, or a selector copied from another manifest. The most common version is subtler: the selector was written against the labels on the Deployment object rather than the labels inside `spec.template.metadata.labels`, which are what the pods actually carry.

Confirm

kubectl get pods -l "$(kubectl get svc <service> -o jsonpath='{.spec.selector}' | tr -d '{}"' | tr ',' ',')" --show-labels

No pods returned. Then compare against `kubectl get pods --show-labels` to see what labels the pods really carry

Fix

  • Make the Service selector match `spec.template.metadata.labels` in the Deployment exactly, key and value.
  • Change the Service rather than relabelling running pods — editing pod labels detaches them from their ReplicaSet and creates duplicates.
  • Keep the selector minimal. Matching on one stable label is more robust than matching on five that include a version.
kubectl get svc <service> -o jsonpath='{.spec.selector}'; echo; kubectl get deploy <deployment> -o jsonpath='{.spec.template.metadata.labels}'

Prints the two things that must agree, next to each other.

The pods match but none are Ready

Common

A pod is added to the endpoint list only once it passes its readiness probe. If the probe checks the wrong path or port, or the application takes longer to start than the probe allows, the pods run indefinitely and are never advertised. The Service is behaving exactly as designed; the probe is the thing that is wrong.

Confirm

kubectl get pods -l app=<label> -o wide

READY showing 0/1 while STATUS is Running. Then `kubectl describe pod <pod>` for the probe failure message

Fix

  • Check the readiness probe's path, port and scheme against what the application actually serves.
  • For a slow starter, use a startup probe rather than inflating the readiness `initialDelaySeconds` — the latter delays every restart for the life of the workload.
  • Confirm the probe from inside the pod before changing the manifest, so you are testing the application rather than guessing.

targetPort does not match the container port

Common

The Service's `port` is what clients call; `targetPort` is where it forwards on the pod. When targetPort names a port the container does not listen on, endpoints can still appear and every connection fails. When targetPort uses a *name*, that name must be defined in the container's ports list — an undefined name resolves to nothing.

Confirm

kubectl get svc <service> -o jsonpath='{.spec.ports[*]}{"\n"}'; kubectl get pod <pod> -o jsonpath='{.spec.containers[*].ports[*]}{"\n"}'

targetPort against containerPort, and whether a named targetPort exists in the container's ports

Fix

  • Set targetPort to the port the process actually binds, which is not always the one documented.
  • Prefer named ports and define the name on the container, so the two sides cannot drift numerically.
  • Verify what the process listens on from inside the pod rather than from the manifest.

The pods are in a different namespace

Occasional

A Service selects only within its own namespace. Applying a Service to `default` while the workload runs in `production` produces a valid Service with an empty endpoint list and no error anywhere. Common after copying a manifest between environments or forgetting `-n` on an apply.

Confirm

kubectl get svc <service> -o jsonpath='{.metadata.namespace}{"\n"}'; kubectl get pods -A -l app=<label> -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name

The Service's namespace differing from where the matching pods actually run

Fix

  • Apply the Service into the namespace the workload runs in.
  • For genuine cross-namespace access, address the Service by its fully qualified name from the other namespace rather than trying to select across the boundary.

There are no pods at all

Occasional

The Service is correct and the workload is not running — scaled to zero, every pod stuck Pending, or a Deployment that failed to roll out. The endpoint list is empty for the simplest possible reason, and looking at the Service wastes time that belongs on the workload.

Confirm

kubectl get deploy,rs,pods -l app=<label>

A Deployment showing 0 available replicas, or no pods listed at all

Fix

  • Establish why the workload is not running before touching the Service — see the Pending and CrashLoopBackOff pages.
  • Check the replica count has not been scaled to zero by an autoscaler or a previous mitigation.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

What is actually happening

A Service does not forward traffic by itself. It selects pods by label, and the control plane maintains the resulting list of addresses as EndpointSlices. When that list is empty, the Service still exists, DNS still resolves its name, and connections to it go nowhere.

That is why the symptom appears everywhere except the Service. An Ingress in front reports 503. A client inside the cluster gets a connection refused or a timeout. Your application logs show nothing at all, because no request ever arrived. The silence is the evidence.

Two things have to be true for an address to appear: a pod must match the selector, and that pod must be Ready. Pods that are running but failing their readiness probe are deliberately excluded — that is the probe doing its job, not a fault in the Service.

One detail catches people repeatedly: matching is on labels, and labels live on the *pod*, not on the Deployment. A Deployment's own labels and the labels in its pod template are different fields, and a Service selecting the former finds nothing.

How to tell this is your problem
WhereWhat you see
kubectl get endpoints <service>ENDPOINTS shows <none>
An Ingress or gateway503, often worded as no healthy upstream
Your application logsNothing — the request never reached a pod
kubectl get podsPods may be Running and still show 0/1 READY

How to know it is actually fixed

  • kubectl get endpoints <service> lists at least one address.
  • A request from inside the cluster to the Service name succeeds — test from a pod, not from your laptop.
  • Delete one pod and confirm the endpoint list drops it and then restores it. An endpoint list that is correct only while nothing changes is not yet correct.
  • If an Ingress was returning 503, confirm it now returns the application's own response rather than assuming it followed.

Stopping it happening again

  • Generate the Service selector from the same labels the Deployment template sets, rather than writing it twice.
  • Give every workload a readiness probe that checks something real, and confirm it fails when the application is genuinely unhealthy.
  • Use named ports so the Service and the container cannot drift apart numerically.
  • Add an endpoint-count check to deploy verification. A rollout that reports success against an empty Service is the failure this page exists for.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Related