Error and warning codes
Every error and warning lamina raises, in Rust, in WebAssembly and in @lamina/pdf, has one of these codes. The tables below are read from fixtures/codes.json when this site is built: the same file cargo xtask gen codes generates the Rust enums and the TypeScript unions from. Each code links to its page on this site, which explains when it happens, why, how to fix it and what its data holds. See Errors and warnings for how to handle them.
Warnings
| Code | Kind | What happened | What to do |
|---|---|---|---|
missing-header | input | no %PDF-x.y header in the first 1,024 bytes; parsing went ahead | nothing to do if the document reads correctly; open in strict mode to refuse such files |
xref-repaired | input | the stored cross-reference data was unusable and was rebuilt by scanning | check the result; save with a full rewrite, since an incremental update refuses a repaired base |
xrefstm-ignored | input | a hybrid file's /XRefStm could not be read and was ignored | nothing to do; the classic xref table is used instead |
stream-length-recovered | input | a stream's /Length was wrong, so its end was found by scanning for endstream | nothing to do; a full rewrite writes the correct length |
stale-generation | input | a reference's generation did not match its xref entry, so it resolved to null | nothing to do; the reference is treated as missing |
page-tree-node-skipped | input | a page-tree node was missing, malformed or too deep, and was skipped | check the page count: pages under the skipped node are missing |
page-count-mismatch | input | the page tree's /Count differs from the number of pages walked | nothing to do; lamina uses the walked page count |
flate-truncated | input | Flate data was truncated or had a bad checksum; the partial output was kept | check the affected content: the end of the stream may be missing |
objstm-index-mismatch | input | an object stream's index was stale and the object was found by searching | nothing to do; a full rewrite writes a correct index |
object-number-out-of-range | limit | an xref entry above max_object_number was dropped | raise max_object_number in Limits only if you trust the input |
aes-padding-invalid | security | AES-encrypted data had a bad length or padding and was kept as stored | treat the affected strings and streams as suspect: they may have been tampered with |
perms-mismatch | security | an R5/R6 document's /Perms does not match its /P and /EncryptMetadata | treat the document's permissions as untrusted |
warnings-truncated | limit | more than max_warnings warnings were raised and the rest were dropped | raise max_warnings in Limits if you need the full list |
invalid-box | input | a page boundary box is not four numbers and reads as absent | nothing to do; the page uses the next box in the fallback chain |
invalid-rotate | input | a page's /Rotate is not a multiple of 90 and reads as 0 | set the page rotation explicitly if 0 is wrong |
name-tree-node-skipped | input | a name- or number-tree node was malformed, repeated or too deep, and was skipped | check the tree's entries: those under the skipped node are missing |
outline-cycle | input | an outline item was reached twice; that branch of the walk stopped | nothing to do; the outline is read without the loop |
outline-item-skipped | input | an outline item was missing, not a dictionary or too deep, and was skipped with its subtree | check the outline: the skipped item and its children are missing |
invalid-date | input | an Info date is not a valid PDF date; the raw string is kept | read the raw value from the Info view if you need it |
invalid-page-label | input | a /PageLabels entry is malformed; the malformed part is dropped | nothing to do; affected pages fall back to decimal labels |
invalid-entry | input | an entry a view reads is unreadable or of the wrong type and reads as absent | nothing to do; the view uses the entry's default |
content-unknown-operator | input | an operator the spec does not define was skipped outside a BX/EX section | nothing to do; check the page's rendering if the operator mattered |
content-bad-operands | input | an operator had too few operands or operands of the wrong type, or extra ones | nothing to do; the operator was skipped or used its last operands |
content-unbalanced-q | input | a Q without a matching q was ignored, or saved graphics states were left open | nothing to do; the graphics state was restored as the spec intends |
content-unbalanced-bt | input | a text object was opened twice, closed outside one, or left open | nothing to do; text operators outside a text object were handled tolerantly |
content-unbalanced-marked | input | an EMC without a matching BMC or BDC was ignored, or marked content was left open | check tagged-content results: marked-content sequences were closed for you |
content-syntax | input | content-stream bytes that are not a token were skipped | check the page's content: the bytes around the reported offset were skipped |
content-resource-missing | input | an operator named a resource that is missing, of the wrong type or unreadable | check the page's resources: the operator ran without the resource or was skipped |
inline-image-unterminated | input | no EI ends an inline image; the rest of the content was skipped | check the page's content: everything after the inline image is missing |
xobject-cycle | input | a Form XObject draws itself, directly or through other forms | nothing to do; the inner Do was skipped |
content-path-unpainted | input | a content stream ended with a path no painting operator ended | nothing to do; the unpainted path was dropped as the spec intends |
font-invalid | input | a font dictionary has a missing or malformed entry, so its text was decoded with defaults | nothing to do; extracted text or positions for that font may be off |
cmap-invalid | input | a font's CMap or ToUnicode CMap is malformed or names a predefined CMap lamina has no table for | nothing to do; the bad entries were skipped and the rest of the CMap is used |
unmapped-glyph | input | a font shows glyphs that nothing maps to text | nothing to do; those glyphs extract as U+FFFD (the file needs a ToUnicode CMap) |
Errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
not-pdf | input | the input does not look like a PDF at all | check that the bytes passed to open are a PDF file |
missing-root | input | no document catalog (/Root) was found, even after repair | use another copy of the file: this one has no usable catalog |
reference-cycle | input | a reference chain or the page tree loops back on itself | use another copy of the file, or repair it with another tool |
limit-exceeded | limit | a hard Limits value was exceeded | the input exceeds a safety limit; raise {limit} in Limits only if you trust the input |
strict | input | strict mode refused something the tolerant reader would have repaired | open without strict mode to read the file with repairs, or fix the file |
data-pending | state | the ByteSource has not fetched the byte ranges the call needs yet | fetch the listed ranges into the source and retry the call |
source | io | the ByteSource failed to read | retry the call, or check the source; the document stays usable |
type | input | an object had a different type than the structure requires | use another copy of the file, or repair it with another tool |
invalid-structure | input | an object stream, xref section or filter parameter was malformed | use another copy of the file, or repair it with another tool |
unset-object | internal | a writer object number was reserved but never given a value | this is a lamina bug: report it with the steps that led to it |
repaired-base | state | an incremental update was requested for a document whose xref needed repair | save with a full rewrite instead of an incremental update |
encrypted-base | unsupported | a save of an encrypted document was requested | saving encrypted documents is not supported yet; use another tool to decrypt or re-encrypt |
password-required | security | the document is encrypted with a user password and none was given | pass the document's password in OpenOptions |
wrong-password | security | the given password is neither the user nor the owner password | ask for the password again and retry with the correct one |
unsupported-security-handler | unsupported | the document uses a security handler lamina cannot decrypt | use a tool that supports this encryption to decrypt the file first |
unexpected-eof | input | the input ended before a complete token or object was read | use a complete copy of the file: this one looks truncated |
syntax | input | a token or structure did not match the PDF grammar | use another copy of the file, or repair it with another tool |
unsupported-filter | unsupported | a stream uses a filter lamina does not implement | use a tool that supports the filter to read this stream |
decompress | input | compressed stream data was corrupt | use another copy of the file: this stream's data is damaged |
Op errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
nested-transaction | state | a transaction was started, or undo or redo called, while one is open | commit or roll back the open transaction first, or use a savepoint inside it |
no-transaction | state | apply, commit or rollback was called without an open transaction | call begin first, or use transact |
unknown-page | usage | an op names a page the document does not have | use a PageId from this document's pages() |
direct-page | unsupported | the page is a direct dictionary, which ops cannot edit yet | rewrite the file so that every page is an indirect object, or wait for page-structure ops |
unsupported-version | unsupported | an op log has a schema version this reader does not know | upgrade lamina to a version that reads this op log version |
invalid-op-log | input | an op log does not parse: an unknown op or field, a bad value, or not JSON | validate the op log against the op schema; the samples in fixtures/ops show the format |
saved-not-rebased | state | the document was saved to a sink lamina cannot read back and waits for rebase | call rebase with the saved bytes before applying ops or saving again |
no-pending-save | state | rebase was called without a save waiting for it | call rebase only after a save that returned SavedNotRebased |
Save errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
sink | io | the sink failed to take the bytes or could not give them back | check the destination and retry the save; the document is unchanged |
not-rebased | state | the output was written, but rebasing the document onto it failed | retry rebase with the saved output carried by the error |
sink-not-empty | usage | the sink already held bytes before the save started | pass an empty sink: output offsets count from the sink's first byte |
would-invalidate-signatures | security | the save would break one or more signatures | save with SaveMode::Auto, or ask the user and retry with SaveOptions::with_invalidate_signatures |
requires-rewrite | state | an incremental save was requested but only a full rewrite is safe | save with SaveMode::Auto or SaveMode::FullRewrite |
Text errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
invalid-font | input | font bytes could not be read as a font | pass the complete bytes of a .ttf, .otf, .ttc or .otc file |
collection-index | usage | a font collection member past the end of the collection was asked for | use an index below Font::collection_len |
unknown-axis | usage | an instance was asked for on a variation axis the font does not have | check the font's axes before choosing coordinates, or use a variable font |
font-not-embeddable | usage | the font's OS/2 fsType forbids embedding | use another font, or register it with EmbedPolicy::Override if your licence allows embedding |
missing-glyph | input | the font has no glyph for a character of the text | use a font that covers the character, or split the text across fonts |
glyph-out-of-range | usage | a glyph ID at or past the font's glyph count was used | pass glyph IDs from the font you registered |
unknown-font | usage | a FontKey was used with a registry that did not hand it out | use the key returned by this registry's add |
subset-failed | unsupported | subsetting a font failed | try another version or format of the font, and report the font if it is a common one |
invalid-axis-value | usage | a variation axis value was NaN or infinite | pass finite axis values; values outside the axis range are clamped |
wrong-document | usage | finish_fonts was given a document the registry did not reserve its fonts in | use one FontRegistry per document and finish it with that document |
invalid-feature | usage | an OpenType feature setting did not parse | write it as liga=0, -liga, smcp or aalt=2 (HarfBuzz syntax without ranges) |
invalid-text-range | usage | a byte range was out of bounds or not on character boundaries of the text | take ranges from lamina's results (line_breaks, itemize, break_lines) and pass the same text |
unsupported-layout-option | unsupported | a layout option that is not implemented yet was asked for | leave the option at its default; justification comes with a later release |
font-mismatch | usage | a shaped run was given with a font key for a different font than it was shaped with | pass the key of the font the run was shaped with (the font index of each line run maps to your keys) |
encoding-full | limit | a standard 14 font has no free one-byte code left for another glyph | embed a font with Font::from_bytes, or split the text across two registrations of the standard font |
font-not-shapable | unsupported | a standard 14 font was given to shaping or layout, which need a font program | draw standard 14 fonts with FontRegistry::encode, or shape with an embedded font |
Text warnings
| Code | Kind | What happened | What to do |
|---|---|---|---|
tounicode-conflict | usage | one glyph was used for two different texts; ToUnicode keeps the first | mark the second occurrence with /ActualText so extraction gets its text |
whole-font-rebuilt | usage | a font that forbids subsetting was rebuilt with every glyph kept | check that the font's licence allows this, or use a static TrueType or CFF version |
Build errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
invalid-image | input | image bytes are not a readable image of the format they were given as | pass the complete bytes of a JPEG or PNG file to Image::jpeg or Image::png |
unsupported-image | unsupported | the image uses a feature that PDF or lamina does not support | convert it to a baseline or progressive 8-bit JPEG, or to PNG |
image-too-large | limit | the image needs more memory than the builder allows (a decoded PNG over 256 MiB, or raw dimensions whose size overflows) | scale the image down before adding it |
image-data-length | usage | raw image samples are not width x height x channels bytes long | pass exactly 4 bytes (RGBA) per pixel, row by row |
invalid-icc-profile | input | the bytes are not a usable ICC profile | pass a complete ICC profile with a Gray, RGB or CMYK data colour space |
color-components | usage | a colour has the wrong number of components for its colour space | give one component per channel of the colour space (/N of the ICC profile) |
invalid-color | usage | a colour string is not of the form #rgb or #rrggbb | write the colour as # followed by 3 or 6 hexadecimal digits |
invalid-geometry | usage | a page size, box, /UserUnit, drawing value (coordinate, matrix, line width, dash, miter limit) or image size is not usable | use finite coordinates, positive page sizes and /UserUnit, non-negative line widths and dashes, a miter limit of at least 1, and images of at least one pixel |
text-overflow | usage | a text box's lines don't all fit its height and its options asked for an error | make the box taller or the text shorter, or use Overflow::Clip and read TextLayout::overflow |
page-index-out-of-range | usage | a link, outline item or destination names a page index the document doesn't have | use a 0-based index below the document's page count |
unknown-destination | usage | a link or outline item names a destination that was never defined | define it with Builder::destination before the build finishes, or link to a page |
invalid-page-labels | usage | page label ranges that don't start at page 0, don't increase, start past the last page or number from 0 | give ranges sorted by first page, the first at page 0, numbered from 1 |
Render errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
render-too-large | limit | the requested tile is larger than the render limits allow; nothing was allocated | request smaller tiles (256 to 512 pixels at high zoom) or raise RenderLimits if the larger bitmap is intended |
render-failed | input | the render engine could not open the document or draw the page | the file may be damaged or use a feature this engine can't draw; try the other backend, or report the file |
render-backend-unavailable | io | the render engine is not available: its library or module could not be loaded | run cargo xtask fetch-pdfium or set LAMINA_PDFIUM_DIR to the folder holding the PDFium library |
Facade errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
cancelled | cancelled | a CancelToken stopped the work; the job is finished and returned no partial result | nothing to do: this is the outcome the caller asked for; start a new job to try again |
job-finished | state | a job was stepped after it had finished, failed or been cancelled | stop stepping a job once a step returned its result or an error; create a new job |
document-changed | state | the document a job was created for changed (an edit, undo, redo, save or rebase) or a different document was passed to step | pass the document the job was created from, and don't change it while the job runs; create a new job |
Binding errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
builder-finished | state | a builder or one of its pages was used after it finished | create a new builder or page: a finished one takes no more drawing, pages, fonts or settings |
invalid-argument | usage | a value passed to a binding does not have the shape its type declares | pass the value the type declarations describe; the data field says what was wrong |
source-budget-exceeded | limit | a sparse source was given more bytes than its byte budget allows | raise the source's budget, or open the file with fewer bytes fetched (smaller blocks, no readahead) |
unknown-option | usage | an options record passed to a binding has a key lamina does not know | remove the key or correct its spelling; didYouMean lists the closest known names |
Package errors
| Code | Kind | What happened | What to do |
|---|---|---|---|
already-initialized | state | init() or loadText() named a different source for a module that is already loaded or loading | call init and loadText with a source once, before the first load; later calls need no source |
extract-module-not-loaded | state | page.text() was called on a document opened in the base module, which has no text extraction | load the extract module (init with the extract option, or loadExtract) or the text module before opening the document |
fetch-failed | io | a range source could not fetch input bytes: a network error, an HTTP status other than 200 and 206, a 206 whose Content-Range or length doesn't match the request, or a read that returned the wrong number of bytes | check that the URL is reachable and that the server sends the CORS headers range requests need (Content-Range must be exposed); data.reason and data.status say what failed |
not-initialized | state | an @lamina/pdf function was called before init() finished loading the WebAssembly module | await init() once before calling anything else in @lamina/pdf |
source-changed | io | a remote file changed while it was being read: its ETag or length differs from the first response | open the file again; the document already read parts of the old version and can't mix in the new one |
text-module-not-loaded | state | a font or text call was made on a builder of the base module, which has no fonts or text | load the text module with init and the text option, or with loadText, before creating the builder that draws text |
disposed | state | a document, builder or other handle was used after free(), or after the using block that held it ended | free a handle only after its last use; to keep working, open the document again or create a new builder |
worker-version-mismatch | usage | the worker answered with a different protocol or package version than the client | serve the worker file from the same @lamina/pdf build as the page; don't load it from a CDN or an older deploy |
worker-crashed | internal | the worker running lamina stopped (an uncaught error, a WebAssembly trap or out of memory); calls in flight were rejected | call client.restart() and open the document again; report the file if it keeps happening |
worker-failed | internal | the worker client failed with an error that isn't lamina's (a bug in @lamina/pdf/worker, or a result it couldn't send) | this is a lamina bug: report it with the call and the message; the worker keeps running |