fix(orb): fail safe on a stream read error in readOrbRelayRegisterBody - #3456
Conversation
Found via Sentry (GITTENSORY-J): a dropped connection or network reset mid-read threw uncaught out of readOrbRelayRegisterBody, which all three callers (POST /v1/orb/token, /v1/orb/relay/register, /v1/orb/relay pull) invoke before their own try/catch -- the exception escaped as a bare framework 500 instead of each route's own clean 4xx/503 JSON response. Wrap the read loop and return null (the same sentinel already used for an oversized payload) on any stream error, fixing all three call sites at the source.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-05 07:52:01 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 5 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3456 +/- ##
=======================================
Coverage 92.99% 92.99%
=======================================
Files 296 296
Lines 30972 30974 +2
Branches 11294 11294
=======================================
+ Hits 28803 28805 +2
Misses 1514 1514
Partials 655 655
🚀 New features to boost your workflow:
|
Closes #3460
Summary
orb_broker_unavailable: Orb broker token exchange failed (500).Seer's suggested framing ("wrap the entire handler in a top-level try-catch") turned out to be imprecise — the/v1/orb/tokenroute (src/api/routes.ts:3175) already wraps its actual token-minting call (brokerOrbToken) in a try/catch that correctly returns a clean503. The real gap:readOrbRelayRegisterBody(src/orb/relay.ts), which reads the raw request body via aReadableStreamreader, is called before that try/catch at all three of its call sites (POST /v1/orb/token,/v1/orb/relay/register,/v1/orb/relaypull). A dropped connection or network reset mid-read throws uncaught out of this function, escaping as a bare framework 500 instead of any route's own clean 4xx/503 JSON response — exactly matching the observed "(500)" in the error text.readOrbRelayRegisterBodyitself and returnnullon any stream error — the same sentinel already used uniformly by all three callers for "payload too large." This is a single-point fix (the function, not each call site) since all three routes already handle thenullcase identically.Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run typecheck(clean)npx vitest run test/integration/orb-relay.test.ts— 77/77 passingvitest --coverage --coverage.include=src/orb/relay.ts): 100% line coverage on the changed function; the one pre-existing uncovered branch (in an unrelated function,shouldPersistRelayFailure) is untouched by this change.npm run test:workers/npm run build:mcp/npm run test:mcp-pack/npm run ui:openapi:check/npm run ui:build— not run individually this PR; no worker/MCP/OpenAPI/UI surface touched.ReadableStreamthat enqueues a partial chunk then errors (simulating a realistic mid-read network drop), assertingreadOrbRelayRegisterBodyresolves tonullinstead of rejecting.Safety
413response fornullalready existed at every call site; this only prevents an additional failure mode from bypassing it as an uncaught exception).UI Evidencesection below. — N/A, no visible UI change.Notes