Repository navigation
fix(sdk): stop the browser client setting user-agent on its OTLP requests - #1338
JeremyFunk wants to merge 1 commit into
Conversation
…ests Firefox sends a script-set user-agent, and the header is not CORS-safelisted, so a cross-origin endpoint that does not allow it rejects the preflight and every OTLP POST with it. The client entry now leaves user-agent to the browser in both MapleFlush.make and Maple.layer; x-maple-sdk still carries the SDK identity. Server and Cloudflare presets are unchanged.
Maple review🟢 Confidence 9/10 · safe to merge Both browser presets stop sending a script-set
Production impactTelemetry this change adds and removes (1)
What was checked
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (12)
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe shared flush builder now controls whether requests include ChangesSDK Header Configuration
Priority: ⚪ Not assessed Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to Browser OTLP requests omit the script-set User-Agent while retaining SDK identity. The available evidence does not establish a current-head Firefox delivery failure; real-browser cross-origin effectiveness remains unverified. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What
The browser client entry (
@maple-dev/effect-sdk/client) no longer setsuser-agenton its OTLP requests. Server and Cloudflare presets are unchanged.buildResolved(shared/flush-core.ts) takes a per-presetsendUserAgent.x-maple-sdkis always set;user-agentonly when the preset asks for it. Client:false. Server, Cloudflare:true.Maple.layer(client) is built on Effect'sOtlp.layerJson, whose exporter setsuser-agent: effect-opentelemetry-<OtlpTracer|OtlpLogger|OtlpMetrics>/0.0.0and merges it over caller headers, so it cannot be overridden throughheaders. The client's HTTP client wrapper (client/consent-http-client.ts) now removes it before the request goes out.buildResolvedand inversion.tsupdated: some browsers do send a script-setuser-agent.Why
User-Agentis not on the Fetch standard's forbidden request-header list, and it is not a CORS-safelisted request header (those areAccept,Accept-Language,Content-Language,Content-Type,Range). A browser that honours a script-set value therefore lists it in the preflight, and an endpoint whose CORS policy does not allow it rejects the preflight and with it the POST.Measured 2026-10-08 against a mock ingest whose CORS answers mirror ingest's allow-list:
user-agentFirefox's preflight:
Access-Control-Request-Headers: authorization,content-type,user-agent,x-maple-sdk. Withuser-agentallowed by the endpoint, Firefox delivers everything.Safari/WebKit: not measured. WebKit's
isForbiddenHeaderName(Source/WebCore/platform/network/HTTPParsers.cpp) does not listUser-Agent, so by source WebKit accepts a script-set value like Firefox does. MDN's forbidden-request-header page names only Chrome as still dropping it (Chromium bug 571722).The ingest allow-list is extended separately. Removing the header on the SDK side also covers proxies and self-hosted collectors that have their own CORS policy.
Headers per preset after this change
user-agentx-maple-sdkMapleFlush.makeservermaple-effect-sdk-server/<v>maple-effect-sdk-cloudflare/<v>MapleFlush.makeclientmaple-effect-sdk-client/<v>Maple.layerclientSession and replay posts were already fine:
ingestHeadersinpackages/browser-sessionnever setsuser-agent.What ingest reads
record_client_identityinapps/ingest/src/main.rsrecords two attributes on the request handler span:maple.sdkfromx-maple-sdk, anduser_agent.originalfromuser-agent(each cut to 128 characters). For the browser client,maple.sdkis unchanged.user_agent.originalbecomes the browser's own string in every browser, which is what Chromium already produced.Every preset that sent
x-maple-sdkstill sends it, somaple.sdkkeeps being recorded. The review bot's "removes attributemaple.sdk" line points atflush-core.ts:93, where only the comment above the header moved.Decisions
/cliententry and the same transport as the browser; there is no React Native branch in the code. It follows the browser path, so the runtime's defaultuser-agentgoes out andx-maple-sdkidentifies the SDK forMapleFlush.make. No runtime detection added to keep it one code path; there is no CORS in React Native, so either choice delivers.Maple.layerandx-maple-sdk: not added here. A new request header has to be allowed by every cross-origin endpoint's CORS policy, which is the same class of change this PR removes.docs/or the landing docs describes the old behaviour, and none was added.Tests
shared/flush-core.test.ts:sendUserAgent: truesets both headers;falsesetsx-maple-sdkonly.client/flushable.test.ts: the client's trace POST carriesx-maple-sdkand nouser-agent(checked case-insensitively).client/layer.test.ts,client/react-native.test.ts: no request fromMaple.layerorMapleFlush.makecarriesuser-agent. Both fail without the change.server/flushable.test.ts,cloudflare/index.test.ts: both presets still senduser-agentequal tox-maple-sdk.Run locally: those six files plus
client/consent-http-client.test.ts, and the package typecheck.A real-browser cross-origin check of this branch (Firefox, Chrome) will be run separately; it has not been run yet.