mozilla/pdf.js · error · Error

doc.dynamicXFAForm is read-only

Error message

doc.dynamicXFAForm is read-only

What it means

PDF.js's scripting sandbox (src/scripting_api) implements the Acrobat JavaScript `doc` object inside a QuickJS sandbox. Per the Acrobat API specification this property is read-only, so the class defines a getter that returns the current value and a setter that unconditionally throws `Error("doc.<prop> is read-only")`. The throw aborts the currently executing sandboxed script event and is reported back to the host. `dynamicXFAForm` indicates whether the form is a dynamic XFA form; pdf.js always returns `false` (static/no XFA) and forbids writes.

Source

Thrown at src/scripting_api/doc.js:351

  set docID(_) {
    throw new Error("doc.docID is read-only");
  }

  get documentFileName() {
    return this._documentFileName;
  }

  set documentFileName(_) {
    throw new Error("doc.documentFileName is read-only");
  }

  get dynamicXFAForm() {
    return false;
  }

  set dynamicXFAForm(_) {
    throw new Error("doc.dynamicXFAForm is read-only");
  }

  get external() {
    // According to the specification this should be `true` in non-Acrobat
    // applications, however we ignore that to avoid bothering users with
    // an `alert`-dialog on document load (see issue 15509).
    return DOC_EXTERNAL;
  }

  set external(_) {
    throw new Error("doc.external is read-only");
  }

  get filesize() {
    return this._filesize;
  }

  set filesize(_) {

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Remove the assignment to `doc.dynamicXFAForm`; read it through the getter instead.
  2. pdf.js does not support dynamic XFA; convert the form to AcroForm or accept static behavior.
  3. If you cannot edit the PDF's embedded script, wrap the statement in try/catch so the rest of the form logic still runs.

Example fix

// before
doc.dynamicXFAForm = true;
// after
// dynamicXFAForm is read-only — drop the assignment; read via doc.dynamicXFAForm
Defensive patterns

Strategy: validation

Validate before calling

// Known read-only doc properties (PDF.js scripting_api/doc.js)
const READONLY_DOC_PROPS = new Set([
  'author','bookmarkRoot','creator','dataObjects','docID',
  'documentFileName','dynamicXFAForm','external','filesize','hidden',
  'hostContainer','icons','info','innerAppWindowRect','innerDocWindowRect',
  'isModal','keywords','modDate'
]);
if (READONLY_DOC_PROPS.has('dynamicXFAForm')) {
  // skip the write; dynamicXFAForm is read-only in pdf.js
  console.warn('doc.dynamicXFAForm is read-only in pdf.js');
} else {
  doc.dynamicXFAForm = value;
}

Type guard

// Known read-only doc properties (PDF.js scripting_api/doc.js)
const READONLY_DOC_PROPS = new Set([
  'author','bookmarkRoot','creator','dataObjects','docID',
  'documentFileName','dynamicXFAForm','external','filesize','hidden',
  'hostContainer','icons','info','innerAppWindowRect','innerDocWindowRect',
  'isModal','keywords','modDate'
]);
const isReadOnlyDocProp = (name) => READONLY_DOC_PROPS.has(name);
// usage: if (!isReadOnlyDocProp('keywords')) doc.keywords = v;

Try / catch

try {
  doc.dynamicXFAForm = value;
} catch (e) {
  // pdf.js throws Error('doc.dynamicXFAForm is read-only')
  if (/is read-only/.test(e.message)) { /* swallow, expected */ }
  else { throw e; }
}

Prevention

When it happens

Trigger: A sandboxed PDF form/script executes an assignment to the property, e.g. `doc.dynamicXFAForm = value;` or `doc.dynamicXFAForm++`. Because the setter always throws (there is no condition), any write attempt triggers it.

Common situations: Scripts ported from desktop Acrobat where XFA flags were toggled; forms that try to stamp runtime state into document metadata on save/open; and PDFs generated by tools that emit non-spec-compliant JavaScript.

Related errors


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