Skip to content

readOrbIngestBody can throw uncaught on a dropped connection, unlike its documented twin readOrbRelayRegisterBody #8330

Description

@JSONbored

Context

src/orb/relay.ts's readOrbRelayRegisterBody wraps its stream-read loop in a try/catch specifically because, per its own doc comment:

the underlying stream itself errors (a dropped connection / network reset mid-read...) — every caller already treats null identically to "reject this request"... fixed once here rather than wrapping all three callers.

export async function readOrbRelayRegisterBody(request: Request, contentLengthHeader: string | null | undefined): Promise<string | null> {
  ...
  try {
    for (;;) {
      const { done, value } = await reader.read();
      ...
    }
    return out + decoder.decode();
  } catch {
    return null;
  }
}

src/orb/ingest.ts's readOrbIngestBody is the same pattern — declared-length check, reader.read() loop, byte-cap check — but has no try/catch:

export async function readOrbIngestBody(request: Request, contentLengthHeader: string | null | undefined): Promise<string | null> {
  const declared = parseContentLength(contentLengthHeader);
  if (declared !== null && declared > MAX_ORB_INGEST_BODY_BYTES) return null;

  const stream = request.body;
  if (!stream) return "";
  const reader = stream.getReader();
  const decoder = new TextDecoder();
  let total = 0;
  let out = "";
  for (;;) {
    const { done, value } = await reader.read();   // can reject — unguarded
    if (done) break;
    total += value.byteLength;
    if (total > MAX_ORB_INGEST_BODY_BYTES) {
      await reader.cancel();
      return null;
    }
    out += decoder.decode(value, { stream: true });
  }
  return out + decoder.decode();
}

Both /v1/orb/ingest and /v1/ams/ingest (src/api/routes.ts) call readOrbIngestBody directly with no surrounding try/catch of their own, and there is no app.onError handler in routes.ts covering this. A dropped connection mid-upload will throw an uncaught rejection out of the route handler instead of the clean 413/400 JSON response the route otherwise returns for an oversized or malformed body — exactly the bug class relay.ts already fixed for its own three call sites. test/integration/orb-relay.test.ts (~line 184-200) explicitly tests the dropped-connection case for readOrbRelayRegisterBody; no equivalent test exists for readOrbIngestBody in test/integration/orb-ingest.test.ts.

Requirements

  • Wrap readOrbIngestBody's read loop in the same try/catch pattern as readOrbRelayRegisterBody in src/orb/relay.ts: on any error from reader.read() (or elsewhere in the loop), return null instead of letting the rejection propagate.
  • Do not change the function's byte-cap or declared-length-check behavior — only add the error handling around the read loop.

Deliverables

  • readOrbIngestBody in src/orb/ingest.ts wraps its stream-read loop in try/catch, returning null on any read error, mirroring readOrbRelayRegisterBody in src/orb/relay.ts.
  • A regression test in test/integration/orb-ingest.test.ts mirroring test/integration/orb-relay.test.ts's dropped-connection case: a request body stream whose reader.read() rejects, asserting readOrbIngestBody returns null (not an uncaught rejection) and that the calling route returns its normal clean error response rather than a framework 500.

Test Coverage Requirements

This repo's Codecov patch gate requires 99%+ coverage of changed lines and branches. Cover both the new catch branch (read rejects → returns null) and confirm the existing successful-read and oversized-body branches remain covered.

Expected Outcome

A dropped connection or network reset mid-upload to /v1/orb/ingest or /v1/ams/ingest now degrades to the same clean 413/400 JSON response every other rejected-body case already produces, instead of an uncaught rejection reaching the framework as a bare 500.

Links & Resources

  • src/orb/ingest.tsreadOrbIngestBody, around line 28-49
  • src/orb/relay.tsreadOrbRelayRegisterBody, the pattern to mirror, around line 168-200
  • test/integration/orb-relay.test.ts — the dropped-connection test to mirror, around line 184-200
  • src/api/routes.ts — the two call sites (/v1/orb/ingest, /v1/ams/ingest)

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions