OTLP metrics exporter never opens a socket on 2.1.252 (possible regression of #50567) — no connection to explicit or default endpoint, no diagnostics
Written by Claude (Opus 5) and posted on my behalf.
Summary
OTEL_METRICS_EXPORTER=otlp silently no-ops on 2.1.252, with the same signature as #50567 (closed): the exporter never opens a socket, nothing is logged, and no error surfaces anywhere. Metrics are collected correctly — they just never leave the process.
Filing as a possible regression of #50567, or evidence that it was not fully fixed.
Environment
- Claude Code 2.1.252 (installed 2026-09-01 via npm/nvm)
- macOS (Darwin 27.0.0), arm64, node v20.19.0
- Receiver: Prometheus with
--web.enable-otlp-receiver
What happens
A live session runs for minutes with telemetry fully configured and exports nothing. lsof on the session PID shows zero non-443 sockets — it never attempts a connection to any collector.
Evidence
1. The receiver is not the problem. Independently proven from the same host:
| test | result |
|---|---|
| POST garbage to the OTLP path | 400 (live receiver, rejecting bad protobuf) |
| POST a valid OTLP JSON payload | 200, and the metric is queryable immediately |
| POST to a bogus path | 404 |
| reachability from node (same runtime) | 400 on garbage — reachable |
2. Explicit endpoint — no connection. Launched with the variables in the real process environment, verified present via ps eww:
CLAUDE_CODE_ENABLE_TELEMETRY=1
OTEL_METRICS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT=http://<collector>/api/v1/otlp
OTEL_METRIC_EXPORT_INTERVAL=10000
Ran several minutes doing real work. lsof -p <pid> showed only HTTPS to the API — zero connections to port 80. Nothing arrived at the collector.
3. Default endpoint — no connection either. To rule out the network path entirely, I ran a 12-line Python HTTP server on 127.0.0.1:4318 (the OTel spec default) that logs every POST and returns 200 {}. Self-tested with curl first, so a silent log means nothing arrived.
Then launched a session with no endpoint set (CLAUDE_CODE_ENABLE_TELEMETRY=1, OTEL_METRICS_EXPORTER=otlp, OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf, OTEL_METRIC_EXPORT_INTERVAL=10000), confirmed via ps eww. It ran ~1 hour, live and busy, at a 10-second export interval.
Result: zero requests to the sink. Zero non-443 sockets held by the process.
Told where to go, it doesn't go. Left to its default, it doesn't go. It does not open a socket to loopback.
4. The metrics themselves are being collected. ~/.claude/statusline-payload.json carries exactly the figures the OTLP metrics are built from, live, for a running session:
cost.total_cost_usd = 30.99
context_window.total_input_tokens = 335490
context_window.total_output_tokens = 366
prompt_cache.cache_write_tokens = 573159
So collection works and the data is on disk. The failure is isolated to the export step.
5. It worked before. The same Prometheus holds claude_code_cost_usage_USD_total, claude_code_session_count_total, claude_code_token_usage_tokens_total and friends with continuous data up to 2026-08-30 17:52 local, then nothing. Metric names and pipeline are known-good.
No diagnostics are available
--debug produces no telemetry output at all:
claude --debug ... 2>/tmp/log→ 0-byte file (debug goes to stdout, which the TUI owns)claude --debug -p "say hi" >/tmp/log 2>&1→ only the model's reply. No[3P telemetry]line, no init message, no error.
There is no observable failure — only absence. Given #50567's finding that the dynamic require() fails inside a try/catch, a logged warning on exporter-construction failure would have turned an hour of black-box bisection into one line.
Difference from #50567
That report's diagnostic was that OTEL_METRICS_EXPORTER=console still works and dumps metrics to stdout. Here it printed nothing across two print-mode runs, one of which ran 40 lines of output — long enough for a 3-second export interval to fire twice.
I could not separate "console exporter is also broken" from "print mode does not initialize telemetry", since an interactive run would put console output into the TUI. Flagging it as unverified rather than asserting it.
Secondary bug: env block in settings.json drops OTEL_* keys
With these five keys in the top-level env block of ~/.claude/settings.json:
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "http://<collector>/api/v1/otlp/v1/metrics",
"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE": "cumulative"
only CLAUDE_CODE_ENABLE_TELEMETRY=1 appears in the session's process environment. All four OTEL_* keys are absent (checked on sessions started well after the settings edit; ps eww shows 49 env entries, none of them OTEL).
The result is telemetry enabled with no endpoint, protocol, or exporter configured — the worst of both states, and silent. If this is intended (applied internally rather than exported), the documentation should say so, because it is indistinguishable from the block being ignored.
What would help
- Log a warning when exporter construction fails instead of swallowing it — this class of bug is otherwise undebuggable from outside.
- Confirm whether #50567 is fixed in some version and whether 2.1.252 regressed.
- Clarify whether
settings.json'senvblock is expected to configure telemetry, or whether the shell environment is required.
Repro
- Run any OTLP receiver (or the 12-line localhost sink above).
CLAUDE_CODE_ENABLE_TELEMETRY=1 OTEL_METRICS_EXPORTER=otlp OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_ENDPOINT=<receiver> OTEL_METRIC_EXPORT_INTERVAL=10000 claude --model haiku- Do some work.
lsof -nP -p <pid> | grep -v :443→ nothing. Receiver logs → nothing.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗