[BUG] OTLP logs export regressed from Content-Length to Transfer-Encoding: chunked in 2.1.191 — breaks Content-Length-requiring OTLP/HTTP endpoints

Resolved 💬 10 comments Opened Jul 1, 2026 by velimattiv Closed Jul 15, 2026

Summary

Between Claude Code 2.1.190 and 2.1.191, the OTLP/HTTP logs exporter changed from sending Content-Length to Transfer-Encoding: chunked. The bundled exporter version (OTel-OTLP-Exporter-JavaScript/0.208.0) and the emitted events are unchanged — only the HTTP body framing flipped. OTLP ingestion endpoints that require Content-Length now reject every export, silently.

Environment

  • Claude Code 2.1.191 – 2.1.197 (current)
  • CLAUDE_CODE_ENABLE_TELEMETRY=1, OTEL_LOGS_EXPORTER=otlp, OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
  • Target: a Content-Length-requiring OTLP/HTTP ingestion endpoint (common for managed/enterprise collectors and cloud ingestion gateways) — e.g. Azure Monitor Data Collection Endpoints.

What breaks

On 2.1.191+ the export request is sent with Transfer-Encoding: chunked and no Content-Length. Endpoints that require Content-Length reject it. Azure Monitor's DCE returns:

HTTP 400 {"code":"MissingContentLengthHeader","message":"Invalid request. Header 'Content-Length' must be specified."}

The identical payload sent with a Content-Length header returns 204.

Regression bisect

Each published binary run against a local capture endpoint:

| Version | Published | Body framing | Strict endpoint |
|---|---|---|---|
| 2.1.185 | 2026-06-20 | Content-Length | ✅ 204 |
| 2.1.190 | 2026-06-24 | Content-Length | ✅ 204 — last good |
| 2.1.191 | 2026-06-24 | chunked | ❌ 400 — first broken |
| 2.1.193 / 2.1.195 | 2026-06-25 / 26 | chunked | ❌ 400 |

All bundle the same OTel-OTLP-Exporter-JavaScript/0.208.0 and emit identical events (api_request, claude_code.*) — so the change is in Claude Code's bundle, not the OpenTelemetry dependency version.

Impact

We ingest Claude Code's OTLP api_request events into Azure Monitor for usage/cost reporting. The 2.1.191 update silently stopped telemetry from landing, and with no client-side error it wasn't obvious where the break was — we chased server-side and network layers before capturing the raw emission and bisecting to the exact version.

Two gaps compounded it: the framing regression (this bug), plus the endpoint's 400 being swallowed with no log — a total outage looks identical to "working." A single warning on a non-2xx OTLP response would make this class of failure obvious.

Reproduction

  1. Configure the OTLP logs exporter (above), pointing OTEL_EXPORTER_OTLP_LOGS_ENDPOINT at a local HTTP server that logs request headers.
  2. Run any command; inspect the captured request.
  3. On 2.1.190: Content-Length: <N>. On 2.1.191+: Transfer-Encoding: chunked, no Content-Length.

Note (pre-empting "chunked is valid HTTP")

Both framings are valid HTTP/1.1. But the OTLP request body is fully buffered before send, so its length is already known — Content-Length is the correct, more interoperable choice: it works with both lenient and strict endpoints, whereas chunked breaks the strict class for no benefit. 2.1.190 did exactly this; 2.1.191 regressed it.

Suggested fix

Restore Content-Length on the OTLP/HTTP logs request (set the header / end(buffer) on the fully-buffered payload instead of streaming it). Optionally, surface non-2xx OTLP export responses in a log line so silent drops are detectable.

View original on GitHub ↗

This issue has 10 comments on GitHub. Read the full discussion on GitHub ↗