Skip to content
Intellira
Kubernetesmedium severity

ServiceNoEndpoints

A Service with no endpoints returns connection refused or timeouts. Causes: selector mismatch, unready pods, port mismatch, or no running pods.

Written by Intellira Engineering, Editorial team

What "Service has no endpoints" means

A Kubernetes Service is a stable virtual IP that load-balances to a set of backing pods. The control plane resolves that set continuously: the endpoint slice controller "automatically creates EndpointSlices for any Kubernetes Service that has a selector specified," and those slices "include references to all the Pods that match the Service selector." If that set is empty, kubectl get endpoints prints <none>, the Service IP has nothing to forward to, and clients get connection refused or a timeout.

Empty endpoints almost always reduce to one of four mechanisms: the selector matches no pod labels, the matching pods are not Ready (so they are excluded), the Service targetPort does not match the container's port, or no pods are running. The fix is different for each, so diagnose first.

Diagnose it

Start at the endpoints, then walk back to the cause.

# Does the Service have endpoints at all?
kubectl get endpoints <service> -n <namespace>
# ENDPOINTS = <none>  -> empty set; keep going

# The modern source of truth (Endpoints is the legacy view)
kubectl get endpointslices -l kubernetes.io/service-name=<service> -n <namespace>

# What does the Service select, and on what ports?
kubectl get svc <service> -n <namespace> -o yaml   # read spec.selector, spec.ports

# Do any pods carry those exact labels, and are they Ready?
kubectl get pods -n <namespace> --show-labels
kubectl get pods -n <namespace> -l <key>=<value>   # use the Service's selector here

Per the Kubernetes Debug Services guide, the checkpoints are exactly: does the Service have any EndpointSlices, does the selector match the pod labels, are the pods Ready, and does the targetPort match the port the application listens on. Each maps to one section below.

Cause 1: selector does not match any pod labels

The Service spec.selector is matched against pod labels verbatim. A typo, a wrong key, or a label that drifted (for example app: web on the Service but app.kubernetes.io/name: web on the pods) means zero pods match, so the controller writes an empty slice. The Kubernetes Connecting Applications to Services tutorial states the selector "will be evaluated continuously and the results will be POSTed to an EndpointSlice that is connected to the Service."

Diagnose by comparing the two sets directly:

# What the Service asks for
kubectl get svc <service> -n <namespace> -o jsonpath='{.spec.selector}'

# What the pods actually have
kubectl get pods -n <namespace> --show-labels

# The decisive test: select pods with the Service's selector
kubectl get pods -n <namespace> -l app=web,tier=frontend
# returns "No resources found" -> the selector matches nothing

Fix by making one side match the other. Edit the Service selector to the labels the pods really carry, or relabel the workload. Selectors are AND-ed, so every key/value in the selector must be present on the pod:

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web        # must equal a label on the pods, key and value
  ports:
    - port: 80
      targetPort: 8080

Blast radius: editing a live Service selector reroutes all traffic the instant it is applied — if the new selector matches a different (or empty) pod set, you cut over or black-hole production in one kubectl apply. Confirm the target pod set with kubectl get pods -l <new-selector> before applying.

A related trap: a Service with no selector at all. The docs note that "this Service has no selector, the corresponding EndpointSlice objects are not created automatically" — you must manage the EndpointSlice yourself. If you expected selector-based behavior, the missing selector field is the bug.

Cause 2: pods are not Ready (failing readiness probe)

This is the cause that fools people, because kubectl get pods shows Running. Running is not Ready. The EndpointSlices docs define an endpoint's ready condition as "a shortcut for checking serving and not terminating," where serving "maps to the Pod's Ready condition." The Pod lifecycle docs are blunt: if a readiness probe fails, "the Pod's IP address is removed from Service endpoints and EndpointSlices," even though the container keeps running. A failing readiness probe does not restart the container — it pulls the pod out of load balancing.

Diagnose with the READY column and the pod's conditions:

# READY shows ready/total containers; 0/1 means not Ready
kubectl get pods -n <namespace> -l app=web

# Why it is not Ready: look for Readiness probe failed events
kubectl describe pod <pod> -n <namespace>
# Conditions: Ready False ; Events: "Readiness probe failed: HTTP probe failed with statuscode: 503"

Fix the underlying readiness signal, not the probe threshold, unless the probe itself is wrong. Common real causes: the app needs longer to warm up (add a startup probe rather than loosening the readiness probe), the probe path returns non-2xx, or the probe targets the wrong port. A correct readiness probe points at a port the container actually serves:

readinessProbe:
  httpGet:
    path: /healthz
    port: 8080        # a port the container listens on
  initialDelaySeconds: 5
  periodSeconds: 10

Tradeoff: there is an escape hatch, spec.publishNotReadyAddresses: true, which per the EndpointSlices docs makes the ready condition "always be true." That publishes not-ready pods as endpoints — appropriate for headless StatefulSet peer discovery, dangerous for a normal load-balanced Service because it routes traffic to pods that declared themselves unable to serve. Do not set it to silence a readiness failure.

Cause 3: containerPort / targetPort mismatch

Here the EndpointSlice may not be empty — it can list addresses — but the port is wrong, so connections are refused. The Service targetPort is "the port the container accepts traffic on," and per the docs "by default and for convenience, the targetPort is set to the same value as the port field." If your container listens on 8080 but the Service port: 80 has no targetPort, it defaults to 80 and forwards to a closed port.

Diagnose by comparing the Service targetPort against what the container serves:

kubectl get svc <service> -n <namespace> \
  -o jsonpath='{.spec.ports[*].targetPort}'      # e.g. 80

# What the container declares
kubectl get pod <pod> -n <namespace> \
  -o jsonpath='{.spec.containers[*].ports[*].containerPort}'   # e.g. 8080

# Endpoints exist but on the wrong port? this confirms it
kubectl get endpointslices -l kubernetes.io/service-name=<service> -n <namespace> -o yaml

Fix by setting targetPort to the port the application listens on. A named port is more robust than a number, because it survives the container changing its port:

# pod / deployment
ports:
  - name: http
    containerPort: 8080
---
# service
ports:
  - port: 80
    targetPort: http     # resolves to containerPort 8080 by name

Note that containerPort is documentation/metadata — a container listens on whatever port its process binds, regardless of containerPort. So also confirm the process is actually bound to that port (kubectl exec plus a local check), not just that the manifest says so.

Cause 4: no pods running at all

If the workload has zero pods — scaled to 0, every replica crash-looping, or the ReplicaSet failing to create pods — there is nothing for the controller to reference, so the slice is empty. This often coincides with a separate failure that is the real story.

Diagnose by counting and inspecting the workload:

kubectl get deploy,rs,pods -n <namespace> -l app=web
# DESIRED 3 / CURRENT 0, or no pods listed

kubectl describe deploy <deployment> -n <namespace>   # replicas, rollout status
kubectl get events -n <namespace> --sort-by=.lastTimestamp | tail -20

Fix depends on why the pod count is zero:

  • Scaled to zerokubectl scale deploy/<name> --replicas=3 -n <namespace>.
  • Pods stuck Pending — the scheduler cannot place them; see pod-pending for the per-node reason.
  • Pods crash-looping — they start, fail, and never reach Ready; see crashloopbackoff.
  • ReplicaSet cannot create pods — quota, admission webhook, or PodSecurity rejection; read the events on the ReplicaSet.

Blast radius is usually low for the Service itself (it is already serving nothing), but the underlying cause may be actively rolling back a deployment, so treat it as a live incident, not a config tweak.

Work the cheapest, highest-yield checks first:

  1. kubectl get endpoints <service> — confirm it is genuinely <none>.
  2. kubectl get pods -l <service-selector> --show-labels — this one command distinguishes Cause 1 (no pods returned), Cause 4 (no pods exist), and Cause 2 (pods returned but READY is 0/1).
  3. If pods are Ready and selected but the Service still refuses connections, you are in Cause 3 — compare targetPort to the listening port.

This sequence is intentional: step 2 collapses three of the four causes into one observation, so you rarely need all four investigations.

Validate the fix

# Endpoints should now list pod IPs and ports
kubectl get endpoints <service> -n <namespace>
# ENDPOINTS   10.244.2.5:8080,10.244.3.4:8080

kubectl get endpointslices -l kubernetes.io/service-name=<service> -n <namespace>
# ADDRESSTYPE IPv4   PORTS 8080   ENDPOINTS 10.244.2.5,10.244.3.4

# End-to-end from inside the cluster
kubectl run probe --rm -it --image=busybox:1.36 --restart=Never -n <namespace> \
  -- wget -qO- http://<service>.<namespace>.svc.cluster.local:80

If endpoints are now correct but the name still will not resolve, the problem has moved to DNS, not endpoints — a different failure mode worth ruling out separately.

Prevention

  • Use named ports end to end (containerPort: name referenced by Service targetPort) so a port change in the container does not silently break the Service.
  • Treat readiness probes as a contract: the probe must check exactly what "ready to serve" means for that app, and CI should catch a probe pointed at the wrong port.
  • Pin selectors to the recommended labels (app.kubernetes.io/name etc.) consistently across Service and workload, so drift between the two is obvious.
  • Alert on empty endpoints for any Service that should always have backends — a Service with zero ready endpoints is a leading indicator of an outage before clients start failing.

How Intellira diagnoses this

Intellira reads the Service spec, the EndpointSlices, and the matching pods' labels and Ready conditions read-only, then reports which of the four mechanisms is in play: selector that matches no labels, selected pods that are not Ready (with the readiness-probe event quoted), a targetPort that does not match the container's listening port, or a workload at zero pods. It correlates an empty slice with the change that caused it — a relabel, a probe edit, a port change, or a scale/rollback — and cites the evidence rather than guessing.

Sources

By Intellira Engineering. AI-assisted draft, reviewed by the Intellira engineering team; claims cited inline; last verified 2026-06-02.

Frequently asked questions

Why does my Service have no endpoints?
The endpoint slice controller only adds a pod to a Service when the pod matches the selector AND is Ready. So "no endpoints" means one of four things: the selector matches no pod labels, the matching pods are not Ready (usually a failing readiness probe), the Service targetPort does not match the port the container listens on, or there are no pods running at all.
My pods are Running but still are not behind the Service — why?
Running is not Ready. Only pods whose Ready condition is true are published as endpoints. A failing readiness probe keeps a Running pod out of the EndpointSlice. Check the READY column in kubectl get pods — it must show all containers ready, e.g. 1/1.
What is the difference between a missing endpoint and a wrong targetPort?
A missing endpoint means the pod IP is not in the EndpointSlice at all (selector, readiness, or no-pods problem). A wrong targetPort means the endpoint exists but points at a port nothing is listening on, so connections to the Service are refused even though kubectl get endpoints shows addresses.

Related errors

Find the root cause of ServiceNoEndpoints on your stack

Connect read-only and Intellira correlates the change behind it across Bitbucket, Jenkins, ArgoCD and Kubernetes — with the evidence to prove it.