can1357/oh-my-pi · error · ArchiveError
Remote archive did not report a valid size in Content-Range
Error message
Remote archive did not report a valid size in Content-Range
What it means
After a successful 206 probe, httpByteSource() derives the archive's total size from the 'Content-Range: bytes 0-0/<total>' header. This throw fires when the header is missing, malformed, or its trailing total is not a non-negative safe integer. The library needs the total size to validate subsequent ranges and to report ByteSource.size, so it refuses to proceed without it.
Source
Thrown at packages/utils/src/ar/source.ts:115
`Remote archive is too large to buffer without range support (${declared} > ${cap} bytes)`,
);
}
const bytes = new Uint8Array(await probe.arrayBuffer());
if (bytes.byteLength > cap) {
throw new ArchiveError(`Remote archive is too large to buffer without range support (> ${cap} bytes)`);
}
return memoryByteSource(bytes);
}
if (probe.status !== 206) {
await probe.body?.cancel();
throw new ArchiveError(`Remote archive request failed (HTTP ${probe.status})`);
}
await probe.body?.cancel();
// `Content-Range: bytes 0-0/12345` carries the total size.
const contentRange = probe.headers.get("content-range");
const total = contentRange ? Number(/\/(\d+)$/.exec(contentRange)?.[1]) : Number.NaN;
if (!Number.isSafeInteger(total) || total < 0) {
throw new ArchiveError("Remote archive did not report a valid size in Content-Range");
}
return {
size: total,
async read(start, end) {
assertValidRange(start, end);
if (start === end) return new Uint8Array(0);
const response = await doFetch(url, {
headers: { ...options.headers, range: `bytes=${start}-${end - 1}` },
});
if (response.status !== 206) {
await response.body?.cancel();
throw new ArchiveError(`Remote archive range request failed (HTTP ${response.status})`);
}
const bytes = new Uint8Array(await response.arrayBuffer());
if (bytes.byteLength !== end - start) {
throw new ArchiveError("Invalid archive: truncated data");
}
return bytes;View on GitHub (pinned to 9690622007)
Solutions
- Fix or replace the server so a 206 response includes 'Content-Range: bytes start-end/total' (required by RFC 7233 for 206 single-range responses)
- Check for stripping proxies/CDNs in front of the archive and bypass or reconfigure them
- Fetch Content-Length via a HEAD request and wrap the bytes yourself with memoryByteSource if the archive is small enough to buffer
- Download to disk and use fileByteSource() as a fallback when the remote server's range implementation is broken
Example fix
// before: server returns 206 without Content-Range — throws
const src = await httpByteSource("https://odd-server.example/a.tar");
// after: learn size via HEAD, buffer locally if within limits
const head = await fetch(url, { method: "HEAD" });
const size = Number(head.headers.get("content-length"));
const src = size < 256 * 1024 * 1024
? memoryByteSource(new Uint8Array(await (await fetch(url)).arrayBuffer()))
: await httpByteSource(url); Defensive patterns
Strategy: fallback
Validate before calling
const res = await fetch(url, { headers: { range: "bytes=0-0" } });
if (res.status === 206 && !res.headers.get("content-range")) {
console.warn("server sends 206 without Content-Range; use local download fallback");
} Try / catch
let src;
try {
src = await httpByteSource(url, { headers });
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("Content-Range")) {
src = await downloadToDiskAndOpen(url); // fileByteSource fallback
} else throw err;
} Prevention
- Test the server once with curl -r 0-0 -i and confirm a Content-Range header appears on the 206
- Avoid nonstandard file servers/proxies in the archive path, or configure them to emit RFC 7233-compliant Content-Range
- Keep a download-to-disk fallback path in code for hosts with broken range implementations
- Prefer mainstream object stores/CDNs that implement range responses correctly
When it happens
Trigger: Calling httpByteSource() against a server that returns 206 but omits Content-Range, sends a malformed value (e.g. 'bytes */*' or missing the /total suffix), or sends a non-integer/negative total — the regex /\/(\d+)$/ then fails to parse and total is NaN.
Common situations: Nonstandard or hand-rolled HTTP file servers that honor Range with 206 but omit the Content-Range header; proxies that strip response headers; multipart/byte-range caches that rewrite headers; HTTP/2 intermediaries dropping custom header casing in exotic setups.
Related errors
- Remote archive is too large to buffer without range support
- Remote archive range request failed (HTTP ${response.status}
- Remote archive request failed (HTTP ${probe.status})
- V2 remote compaction failed (${response.status} ${response.s
- No response body for V2 compaction streaming
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c6c0f2a8288bb7f5.
Report an issue: GitHub.