santifer/career-ops · error · Error

the index response carried no readable body: ${url}

Error message

the index response carried no readable body: ${url}

What it means

downloadAsset() streams the response body via res.body.getReader(); if the 200 response carries no body, or a body that is not a readable stream (no getReader method), the download cannot be hashed or written and this error is thrown. This catches odd runtime environments and proxies that strip or replace bodies.

Source

Thrown at plugins/h1b-sponsor/install-h1b-index.mjs:152

}

/**
 * Stream the asset to `tmpFile`, hashing as it goes, and return the digest.
 *
 * Streamed rather than buffered: the body is millions of times the size of
 * anything else this plugin reads, and readBoundedText's 1 MiB ceiling exists
 * precisely because nothing on the API path should ever be this big. Hashing
 * during the write means the file is never read a second time to verify it.
 */
async function downloadAsset(fetchImpl, url, tmpFile) {
  return fetchImpl(url, { timeoutMs: ASSET_TIMEOUT_MS }, async res => {
    if (res.status !== 200) throw new Error(`could not download the index (HTTP ${res.status}): ${url}`);
    const declared = Number(res.headers?.get?.('content-length'));
    if (Number.isFinite(declared) && declared > MAX_INDEX_BYTES) {
      throw new Error(`the published index exceeds ${MAX_INDEX_BYTES} bytes (${declared}): ${url}`);
    }
    if (!res.body || typeof res.body.getReader !== 'function') {
      throw new Error(`the index response carried no readable body: ${url}`);
    }

    const hash = createHash('sha256');
    const out = createWriteStream(tmpFile);
    // A write failure (disk full, an unwritable target) arrives as an 'error'
    // event on the stream, and an EventEmitter error with no listener is an
    // uncaughtException: the CLI died on a stack trace instead of returning
    // the envelope, and the cleanup that removes the partial .tmp file never
    // ran. Recording the error here makes the crash impossible; the checks
    // below turn it into the ordinary failure it is. once(out, 'drain') needs
    // no extra wiring, it already rejects when 'error' fires mid-wait.
    let writeError = null;
    out.on('error', err => { writeError = err; });
    const reader = res.body.getReader();
    let total = 0;
    try {
      for (;;) {
        if (writeError) {

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Check what fetchImpl you pass to the installer — if custom, make it return a Response whose body is a Web ReadableStream.
  2. Remove a proxy shim/interceptor that strips response bodies, or upgrade it to a fetch-compatible implementation.
  3. Confirm your Node.js version has native fetch with web-stream bodies (Node 18+), or use a runtime-supported fetch.
  4. Retry against the default endpoint with the built-in fetch to isolate the custom client as the cause.

Example fix

// before
const fetchImpl = () => Promise.resolve({ status: 200, headers: new Headers(), body: Buffer.alloc(0) })
// after
const fetchImpl = (url, opts, onRes) => fetch(url, opts).then(async res => ({ status: res.status, headers: res.headers, body: res.body, text: await onRes(res) }))
Defensive patterns

Strategy: type-guard

Validate before calling

const res = await fetch(assetUrl);
if (!res.body || typeof res.body.getReader !== 'function') {
  throw new Error('your fetch client returns a response without a Web ReadableStream body; the installer cannot stream it');
}

Type guard

function hasReadableBody(res) {
  return !!res.body && typeof res.body.getReader === 'function';
}

Try / catch

try {
  await installH1BIndex();
} catch (e) {
  if (String(e.message).includes('no readable body')) {
    console.error('Custom fetchImpl or runtime returns a non-stream body; use native fetch (Node 18+).');
  } else throw e;
}

Prevention

When it happens

Trigger: The asset response is 200 with an acceptable Content-Length, but res.body is null/undefined or lacks a getReader function when downloadAsset inspects it.

Common situations: A custom fetchImpl was injected (tests, CI shim, proxy client) that returns responses without a Web ReadableStream body; a HEAD-like or empty response from a misbehaving proxy; a Node version/runtime where the fetch polyfill exposes a different body shape (e.g. a Buffer or Node stream instead of a web stream).

Related errors


AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/3a9074c9dbea0301. Report an issue: GitHub.