mozilla/pdf.js · error · Error

doc.selectedAnnots is read-only

Error message

doc.selectedAnnots is read-only

What it means

`Doc.selectedAnnots` returns the array of currently selected annotations; PDF.js returns `[]` because the scripting sandbox does not expose annotation selection state. It is read-only per the Acrobat spec — selection is driven by user input/UI, not settable programmatically through this property. The throwing setter enforces that.

Source

Thrown at src/scripting_api/doc.js:631

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

  get securityHandler() {
    return this._securityHandler;
  }

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

  get selectedAnnots() {
    return [];
  }

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

  get sounds() {
    return [];
  }

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

  get spellDictionaryOrder() {
    return this._spellDictionaryOrder;
  }

  set spellDictionaryOrder(spellDictionaryOrder) {
    this._spellDictionaryOrder = spellDictionaryOrder;
  }

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Remove the assignment; read the value (`var a = doc.selectedAnnots;`, `[]` in PDF.js).
  2. Drive annotation selection through the viewer's annotation layer APIs, not the scripting `Doc` object.
  3. Run legacy scripts under try/catch.

Example fix

// before
doc.selectedAnnots = [annot1, annot2];

// after
var sel = doc.selectedAnnots; // read-only; [] in PDF.js
Defensive patterns

Strategy: try-catch

Validate before calling

const READ_ONLY_DOC_PROPS = new Set(['selectedAnnots','sounds' /* ... */]);
function assertsNoReadOnlyWrite(scriptSrc) {
  for (const p of READ_ONLY_DOC_PROPS) {
    if (new RegExp(`\\bdoc\\.${p}\\s*=[^=]`).test(scriptSrc)) {
      throw new Error(`Script writes read-only property doc.${p}`);
    }
  }
}
assertsNoReadOnlyWrite(myScript);

Type guard

function isReadOnlyDocProp(doc, prop) {
  const desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(doc), prop)
    || Object.getOwnPropertyDescriptor(doc, prop);
  return !!desc && !!desc.get && !desc.set;
}
isReadOnlyDocProp(doc, 'selectedAnnots'); // true

Try / catch

try {
  doc.selectedAnnots = [annot];
} catch (e) {
  if (/selectedAnnots is read-only/.test(e.message)) console.warn(e.message);
  else throw e;
}

Prevention

When it happens

Trigger: A script writes `doc.selectedAnnots = [...];` to force a selection. The setter throws on assignment.

Common situations: Annotation workflows ported from Acrobat; code that assumes selection is settable; scripts that batch-edit annotations.

Related errors


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