OpenTelemetry Error Guide: 'listen tcp 0.0.0.0:4317: bind: address already in use' — Fix Collector Port Conflicts
Fix the Collector 'address already in use' error on OTLP ports 4317/4318: find the process holding the port and resolve duplicate or hostPort clashes.
- #opentelemetry
- #observability
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
At startup the Collector binds a listening socket for each receiver and extension. If another process — or another part of the same config — already holds that port, the bind fails and the Collector refuses to start:
Error: cannot start pipelines: listen tcp 0.0.0.0:4317: bind: address already in use
The HTTP OTLP port and internal endpoints raise the same error:
Error: failed to start extension: listen tcp 0.0.0.0:4318: bind: address already in use
Error: listen tcp :8888: bind: address already in use # Collector's own telemetry port
This is a fatal startup error: no receivers come up, so nothing is collected until the conflict is resolved.
Symptoms
- Collector exits immediately with
bind: address already in use; pod is in CrashLoopBackOff. - The named port is a standard OTLP port (4317 gRPC, 4318 HTTP) or an internal one (8888 metrics, 13133 health, 1777 pprof, 55679 zpages).
- Started after adding a second receiver, running two Collectors on one host, or a previous instance didn’t exit cleanly.
netstat/ssshows another PID already listening on the port.- Two hostPort-mapped DaemonSet pods land on the same node.
Common Root Causes
- Two receivers on the same port — e.g.
otlpandotlp/2both bound to0.0.0.0:4317. - Another Collector/agent running — a second Collector, a vendor agent, or a leftover process holds the port.
- Stale process after a crash — the previous Collector didn’t release the socket before restart.
- hostPort conflict — a DaemonSet using
hostPort: 4317collides with a node-local process or another pod. - Port reused by an unrelated service — something else on the host already listens on 4317/4318.
- Duplicate extension endpoints — two extensions configured on the same internal port.
Diagnostic Workflow
Identify what already holds the port. On the host or inside the container:
ss -ltnp | grep -E ':4317|:4318|:8888'
# or
sudo lsof -iTCP:4317 -sTCP:LISTEN
Check the config for two receivers (or extensions) sharing an endpoint — each listening socket must be unique:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
# DUPLICATE bind below would cause the error:
# otlp/legacy:
# protocols:
# grpc:
# endpoint: 0.0.0.0:4317 # <- same port, conflict
In Kubernetes, look for hostPort collisions and multiple Collectors on a node:
kubectl get pods -A -o wide | grep -i collector
kubectl -n observability get ds otel-agent -o yaml | grep -i hostPort
kubectl -n observability logs ds/otel-agent --previous | grep -i 'address already in use'
If a stale process holds the port, stop it (or let the orchestrator reschedule) and confirm the port is free:
sudo systemctl stop otelcol # or kill the stale PID from lsof
ss -ltnp | grep :4317 # should return nothing before restart
Example Root Cause Analysis
A node running the OTLP agent as a DaemonSet with hostPort: 4317 also had a legacy vendor tracing agent installed on the same host, also listening on 4317. On nodes where both scheduled, the OTel agent crash-looped with listen tcp 0.0.0.0:4317: bind: address already in use, while nodes without the legacy agent were fine — explaining why only some pods failed.
ss -ltnp | grep :4317 on an affected node showed the vendor agent’s PID holding the port. Because the two agents genuinely needed different lifecycles, the OTel agent’s gRPC receiver was moved to 0.0.0.0:4327 with the sending SDKs updated accordingly, and the hostPort was changed to match. After the change every DaemonSet pod bound successfully and the crash loop cleared.
Prevention Best Practices
- Keep every receiver and extension endpoint on a unique port within a config; never bind two components to the same host:port.
- Avoid running a second Collector or vendor agent on the same host/port; if unavoidable, assign distinct ports deliberately.
- For DaemonSets using
hostPort, ensure no node-local process claims the same port, and reserve OTLP ports fleet-wide. - Set a health_check extension and readiness probe so a failed bind is visible immediately rather than a silent no-data condition.
- On restarts, ensure clean shutdown (proper SIGTERM handling) so sockets are released before the new instance binds.
Quick Command Reference
# Find what holds the OTLP ports
ss -ltnp | grep -E ':4317|:4318'
sudo lsof -iTCP:4317 -sTCP:LISTEN
# See the crash reason
kubectl -n observability logs ds/otel-agent --previous | grep -i 'already in use'
# Check for hostPort clashes
kubectl -n observability get ds otel-agent -o yaml | grep -i hostPort
# Confirm the port is free before restart
ss -ltnp | grep :4317
Conclusion
bind: address already in use means something already owns the port the Collector wants — a duplicate receiver in the config, a second agent, a stale process, or a hostPort clash. Locate the holder with ss/lsof, then either free the port or move the Collector’s endpoint to a unique one. Reserving OTLP ports fleet-wide and ensuring clean shutdowns keeps bind conflicts from crash-looping your collection layer.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.