mozilla/pdf.js · error · FormatError
invalid key length
Error message
invalid key length
What it means
Thrown after recovery attempts when the resolved key length is not an integer, is below 40 bits, or is not a multiple of 8. pdf.js tries the Encrypt dict's Length, falls back to 40 for V<=3, and probes the default crypt filter (CF/StmF) for V>=4—if none yields a valid value, the key length is unusable.
Source
Thrown at src/core/crypto.js:1101
keyLength = 40;
} else {
// Trying to find default handler -- it usually has Length.
const cfDict = dict.get("CF");
const streamCryptoName = dict.get("StmF");
if (cfDict instanceof Dict && streamCryptoName instanceof Name) {
cfDict.suppressEncryption = true; // See comment below.
const handlerDict = cfDict.get(streamCryptoName.name);
keyLength = handlerDict?.get("Length") || 128;
if (keyLength < 40) {
// Sometimes it's incorrect value of bits, generators specify
// bytes.
keyLength <<= 3;
}
}
}
}
if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) {
throw new FormatError("invalid key length");
}
let cf = null;
let stmf = Name.get("Identity");
let strf = Name.get("Identity");
let eff = stmf;
if (algorithm >= 4) {
cf = dict.get("CF");
if (cf instanceof Dict) {
// The 'CF' dictionary itself should not be encrypted, and by setting
// `suppressEncryption` we can prevent an infinite loop inside of
// `XRef_fetchUncompressed` if the dictionary contains indirect
// objects (fixes issue7665.pdf).
cf.suppressEncryption = true;
}
stmf = dict.get("StmF") || Name.get("Identity");
strf = dict.get("StrF") || Name.get("Identity");View on GitHub (pinned to 5903d58d58)
Solutions
- Re-save the PDF with Acrobat or qpdf so the Encrypt dict carries a valid Length (e.g., 128 or 256).
- If generating PDFs, ensure Length is in bits and a multiple of 8 between 40 and 256.
- Pre-validate and reject malformed PDFs with a clear message.
Example fix
// before
const doc = await getDocument({ url }).promise;
// after
try {
const doc = await getDocument({ url }).promise;
} catch (e) {
if (e.message === 'invalid key length') {
throw new Error('Encryption key length is malformed; re-save the PDF with a supported producer.');
}
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
const doc = await getDocument({ url }).promise;
} catch (e) {
if (e.name === 'FormatError' && e.message === 'invalid key length') {
notifyUser('Encryption key length is malformed; please re-save the PDF.');
return;
}
throw e;
} Prevention
- Validate producer output with qpdf --check before publishing.
- Reject PDFs whose Encrypt dict Length is non-standard at ingestion.
- Keep a repair step (qpdf --encrypt re-encryption) in your ingestion pipeline.
When it happens
Trigger: Encrypt dict with a fractional or absurdly small Length entry; a CF default handler whose Length is non-numeric; a producer that emitted Length in bytes that fell outside the recovery heuristic (the code shifts <<3 only when <40).
Common situations: Buggy or hand-rolled PDF generators that write Length as bytes (e.g., 16) below the recovery threshold, or as a non-integer; corrupt Encrypt dict.
Related errors
- unknown encryption method
- unsupported encryption algorithm
- Invalid crypt filter name.
- Unknown crypto method
- No password given
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/bf241a3efe971269.
Report an issue: GitHub.