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.

Solutions

  1. 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)
  2. Check for stripping proxies/CDNs in front of the archive and bypass or reconfigure them
  3. Fetch Content-Length via a HEAD request and wrap the bytes yourself with memoryByteSource if the archive is small enough to buffer
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/c6c0f2a8288bb7f5. Report an issue: GitHub.

Appendix: 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)