Hmbown/CodeWhale · error · Error

response exceeds size limit

Error message

response exceeds size limit

What it means

Second half of readBoundedResponse()'s bound: when the response is streamed (no usable Content-Length), it accumulates chunks and throws as soon as the running byte total exceeds maxBytes. This enforces the same size cap as the header check but for chunked responses, then cancels the reader.

Solutions

  1. Narrow the PostgREST query with filters and select so only required rows are returned
  2. Compare the real response size (curl | wc -c) against MAX_ENVELOPE_BYTES
  3. Raise MAX_ENVELOPE_BYTES if envelopes legitimately exceed the current limit
  4. Check for Supabase error responses being returned with 200 and a large body
Defensive patterns

Strategy: validation

Validate before calling

const head = await fetch(url, { method: 'HEAD' });
if (Number(head.headers.get('content-length') ?? 0) > MAX_BYTES) throw new Error('too large');

Try / catch

try {
  const data = await readBoundedResponse(res);
} catch (e) {
  if (e.message === 'response exceeds size limit') console.error('Streamed body grew past cap; fix query filters or raise the cap');
  throw e;
}

Prevention

When it happens

Trigger: A chunked (Transfer-Encoding: chunked) PostgREST response whose accumulated body bytes exceed MAX_ENVELOPE_BYTES, typically a query returning far more rows than expected.

Common situations: Forgetting the select=id or slug filter so the whole facts_channel/facts_key table is downloaded; a misconfigured Supabase returning an error page as a large HTML body; publishing envelopes that have legitimately grown beyond the cap.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/dad5dba16c6a2333. Report an issue: GitHub.

Appendix: source

Thrown at web/scripts/facts-publish.mjs:486

  return text ? JSON.parse(text) : null;
}

export async function readBoundedResponse(response, maxBytes = MAX_ENVELOPE_BYTES) {
  const length = response.headers.get("content-length");
  if (length !== null && (!/^\d+$/.test(length) || Number(length) > maxBytes)) {
    await response.body?.cancel();
    throw new Error("response exceeds size limit or has invalid length");
  }
  if (!response.body) return "";
  const reader = response.body.getReader();
  const chunks = [];
  let size = 0;
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) break;
      size += value.byteLength;
      if (size > maxBytes) throw new Error("response exceeds size limit");
      chunks.push(value);
    }
  } catch (error) { try { await reader.cancel(); } catch { /* Keep rejection. */ } throw error; }
  finally { reader.releaseLock(); }
  return new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks, size));
}

function readJson(path) {
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(readBoundedFile(path)));
}

function nowIso() {
  return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
}

async function main(argv) {
  const { positional, flags } = parseArgs(argv);
  const cmd = positional[0];

View on GitHub (pinned to 433685b202)