mozilla/pdf.js · error · Error
Bad end offset: ${end}
Error message
Bad end offset: ${end} What it means
Thrown by ChunkedStream.onReceiveData when a delivered chunk's end position (begin + chunk.byteLength) is neither aligned to chunkSize nor exactly equal to the document's total byte length. The library enforces this so its internal _loadedChunks set stays consistent with the chunk grid. A violation means the byte-range transport and the configured chunkSize disagree about chunk boundaries.
Source
Thrown at src/core/chunked_stream.js:71
get numChunksLoaded() {
return this._loadedChunks.size;
}
get isDataLoaded() {
return this.numChunksLoaded === this.numChunks;
}
onReceiveData(begin, chunk) {
const chunkSize = this.chunkSize;
if (begin % chunkSize !== 0) {
throw new Error(`Bad begin offset: ${begin}`);
}
// Using `this.length` is inaccurate here since `this.start` can be moved
// (see the `moveStart` method).
const end = begin + chunk.byteLength;
if (end % chunkSize !== 0 && end !== this.bytes.length) {
throw new Error(`Bad end offset: ${end}`);
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
chunk instanceof ArrayBuffer,
"onReceiveData - expected an ArrayBuffer."
);
}
this.bytes.set(new Uint8Array(chunk), begin);
const beginChunk = Math.floor(begin / chunkSize);
const endChunk = Math.floor((end - 1) / chunkSize) + 1;
for (let curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
// Since a value can only occur *once* in a `Set`, there's no need to
// manually check `Set.prototype.has()` before adding the value here.
this._loadedChunks.add(curChunk);
}
}View on GitHub (pinned to 5903d58d58)
Solutions
- Align server Range responses to the rangeChunkSize value passed to getDocument so every served chunk starts and ends on a chunkSize boundary.
- Verify Content-Range and Content-Length headers agree with the byte range the client requested.
- If you implement a custom IPDFFileStreamReader/NetworkLayer, return chunks whose begin and end are multiples of chunkSize (the final chunk excepted).
- Disable range requests via getDocument({ disableRange: true }) when the server cannot honor aligned ranges.
Example fix
// before
stream.onReceiveData(begin, chunk); // begin=5000, chunkSize=65536
// after
const cs = stream.chunkSize;
const end = begin + chunk.byteLength;
if (begin % cs === 0 && (end % cs === 0 || end === stream.bytes.length)) {
stream.onReceiveData(begin, chunk);
} else {
console.warn('Ignoring mis-aligned chunk', { begin, end, cs });
} Defensive patterns
Strategy: validation
Validate before calling
// Validate chunk alignment before invoking onReceiveData
function safeReceiveData(stream, begin, chunk) {
const cs = stream.chunkSize;
const end = begin + chunk.byteLength;
if (begin % cs !== 0) {
console.warn('begin not aligned', { begin, cs });
return false;
}
if (end % cs !== 0 && end !== stream.bytes.length) {
console.warn('end not aligned', { end, cs, total: stream.bytes.length });
return false;
}
stream.onReceiveData(begin, chunk);
return true;
} Prevention
- Set rangeChunkSize to a value the server can honor exactly for every served range.
- Use disableRange: true for servers that ignore or mangle Range headers.
- Inspect Content-Range/Content-Length headers in DevTools before wiring up a custom transport.
- If implementing a custom stream reader, return chunks aligned to chunkSize boundaries.
When it happens
Trigger: Calling onReceiveData(begin, chunk) where (begin + chunk.byteLength) % chunkSize !== 0 and the end is not the final byte. Occurs when a Range-request server returns responses whose sizes differ from the client's rangeChunkSize, when Content-Range/Content-Length disagree, or when a custom network/stream-reader layer passes mis-sized chunks.
Common situations: Self-hosted PDF behind a CDN or reverse proxy that re-chunks responses; mismatched rangeChunkSize between client and origin server; multi-part/byteranges responses served in arbitrary pieces; a server that ignores Range headers and streams the whole file split arbitrarily.
Related errors
- Bad begin offset: ${begin}
- Expected range response-origin "${rangeOrigin}" to match "${
- Parent must be a dictionary.
- Kids must be an array.
- Kid must be a reference.
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/f59c889a50c49a00.
Report an issue: GitHub.