[BUG] otelHeadersHelper did not return a valid value on Windows — helper binary never invoked at time of error

Resolved 💬 6 comments Opened Mar 27, 2026 by JasonCubic Closed May 17, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The PeriodicExportingMetricReader reports otelHeadersHelper did not return a valid value on Windows every 60 seconds, even though the configured helper binary returns valid JSON every time it is actually called.

We instrumented our helper with forensic diagnostic logging that captures the exact bytes written to stdout using a write-before-and-after pattern (writes a "started" entry before any work, then a "completed" entry with the raw stdout_json after writing output). This proves:

| Time (UTC) | Event | Detail |
| ---------- | ----------------- | -------------------------------------------------------------------------------- |
| 18:16:22 | Helper called | started + completed entries, valid JSON captured in stdout_json |
| 18:17:11 | Claude Code error | otelHeadersHelper did not return a valid valueno started entry exists |

The helper binary was never invoked at the time of the error. Our diagnostic log has no started entry at 18:17:11, meaning Claude Code's process never spawned.

The helper output (captured byte-for-byte): clean JSON object with string key-value pairs, no BOM, no \r, no stderr bleed, \n terminator, completes in 5–35ms.

What Should Happen?

When otelHeadersHelper is configured and the helper binary returns valid JSON (object with string key-value pairs), the PeriodicExportingMetricReader should successfully use those headers for metric export. The error should not appear.

Error Messages/Logs

2026-03-27T18:17:11.356Z [ERROR] [3P telemetry] OTEL diag error: {
  "message": "PeriodicExportingMetricReader: metrics export failed (error Error: otelHeadersHelper did not return a valid value)",
  "sourceURL": "B:/~BUN/root/src/entrypoints/cli.js",
  "line": "2717",
  "column": "307976",
  "stack": "Error: PeriodicExportingMetricReader: metrics export failed (error Error: otelHeadersHelper did not return a valid value)\n    at _doRun (B:/~BUN/root/src/entrypoints/cli.js:2717:307976)\n    at processTicksAndRejections (native:7:39)"
}

Steps to Reproduce

  1. On Windows, configure otelHeadersHelper in ~/.claude/settings.json pointing to a Go binary that outputs valid JSON headers:

``json
{
"otelHeadersHelper": "C:/path/to/credential-provider.exe otel-helper --profile my-profile",
"env": {
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel-collector.example.com",
"OTEL_METRICS_EXPORTER": "otlp"
}
}
``

  1. Start Claude Code in VS Code
  2. Open the "Anthropic.claude-code.Claude VSCode" output channel
  3. Within 60 seconds, observe the PeriodicExportingMetricReader: metrics export failed error
  4. The error repeats every 60 seconds indefinitely

Note: The helper binary completes in 5–35ms. The bug may be related to Bun's spawnSync not capturing stdout from fast-completing processes on Windows.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.84 (VS Code extension, anthropic.claude-code-2.1.84-win32-x64)

Platform

AWS Bedrock

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

Suspected root cause: The helper's 29-minute debounce cache (CLAUDE_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS, default 1,740,000ms) means PeriodicExportingMetricReader (60s interval) serves from cache. From decompiling the extension binary, the code path is:

let result = spawnSync(command, { timeout: 30000, shell: true })
  ?.toString()
  .trim();
if (!result) throw Error("otelHeadersHelper did not return a valid value");
// on success: cache = parsed; lastCall = Date.now();

If the first invocation after process start fails to capture stdout (Bun's spawnSync with shell: true on Windows for fast-completing processes), the empty/null result is never cached (the function throws before caching), so every subsequent 60-second metric tick re-throws the same error without re-invoking the helper — because the function throws before reaching the cache-set line.

This is distinct from #35207 (gRPC protocol issue) — we use http/protobuf.

View original on GitHub ↗

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