mozilla/pdf.js · error · FormatError

unsupported encryption algorithm

Error message

unsupported encryption algorithm

What it means

Thrown when the encryption dictionary's V entry is missing, not an integer, or not one of the supported algorithm codes 1, 2, 4, or 5. V selects the encryption algorithm version; V=3 (a deprecated variable-length RC4 variant) and any newer/unknown V value are not implemented. The PDF cannot be decrypted.

Source

Thrown at src/core/crypto.js:1074

    }
    const hash = calculateMD5(key, 0, i);
    return hash.subarray(0, Math.min(n + 5, 16));
  }

  constructor(dict, fileId, password) {
    const filter = dict.get("Filter");
    if (!isName(filter, "Standard")) {
      throw new FormatError("unknown encryption method");
    }
    this.filterName = filter.name;
    this.dict = dict;
    this.#fileId = fileId;
    const algorithm = dict.get("V");
    if (
      !Number.isInteger(algorithm) ||
      (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5)
    ) {
      throw new FormatError("unsupported encryption algorithm");
    }
    this.algorithm = algorithm;
    let keyLength = dict.get("Length");
    if (!keyLength) {
      // Spec asks to rely on encryption dictionary's Length entry, however
      // some PDFs don't have it. Trying to recover.
      if (algorithm <= 3) {
        // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value.
        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) {

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Re-encrypt the PDF with a supported algorithm (V=2 RC4-40/128, V=4 AES-128/RC4, or V=5 AES-256) via qpdf or Acrobat.
  2. If V is corrupt, repair the xref/Encrypt dict with qpdf --check or by re-saving through Acrobat.
  3. Surface an 'unsupported encryption algorithm' user message rather than propagating the FormatError.

Example fix

// before
const doc = await getDocument({ url, password }).promise;

// after — map to a user-facing message
try {
  const doc = await getDocument({ url, password }).promise;
} catch (e) {
  if (e.message === 'unsupported encryption algorithm') {
    throw new Error('Unsupported encryption algorithm (V=' + (e.detail ?? 'unknown') + '). Only V=1,2,4,5 are supported.');
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const doc = await getDocument({ url }).promise;
} catch (e) {
  if (e.name === 'FormatError' && e.message === 'unsupported encryption algorithm') {
    notifyUser('Unsupported encryption algorithm; only V=1,2,4,5 are supported.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Loading a PDF with V=3 (rare legacy producers); a PDF whose /Encrypt dict has a missing or non-integer V entry due to corruption; a PDF using a hypothetical future algorithm code pdf.js has not adopted.

Common situations: Corrupt/truncated Encrypt dict from a bad download or buggy producer; very old PDFs that used V=3 RC4 variants; hand-edited PDFs where V was altered.

Related errors


AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13). Data as JSON: /api/errors/09a617dab58a70e4. Report an issue: GitHub.