{"record":{"id":"60dfbebe7f8fca04","repo":"mozilla/pdf.js","slug":"doc-numfields-is-read-only","errorCode":null,"errorMessage":"doc.numFields is read-only","messagePattern":"doc\\.numFields is read-only","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/scripting_api/doc.js","lineNumber":526,"sourceCode":"\n  set noautocomplete(noautocomplete) {\n    this._noautocomplete = noautocomplete;\n  }\n\n  get nocache() {\n    return this._nocache;\n  }\n\n  set nocache(nocache) {\n    this._nocache = nocache;\n  }\n\n  get numFields() {\n    return this._numFields;\n  }\n\n  set numFields(_) {\n    throw new Error(\"doc.numFields is read-only\");\n  }\n\n  get numPages() {\n    return this._numPages;\n  }\n\n  set numPages(_) {\n    throw new Error(\"doc.numPages is read-only\");\n  }\n\n  get numTemplates() {\n    return 0;\n  }\n\n  set numTemplates(_) {\n    throw new Error(\"doc.numTemplates is read-only\");\n  }\n","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/scripting_api/doc.js#L508-L544","documentation":"`Doc.numFields` returns the count of interactive fields in the document, backed by `this._numFields` (derived from the field map built when the document is parsed). Acrobat defines it as read-only because field count only changes through `addField`/`removeField`, not by direct assignment. PDF.js's throwing setter enforces that contract so scripts get an immediate, spec-consistent failure instead of a silently-ignored write.","triggerScenarios":"A script writes `doc.numFields = n;` or `doc.numFields++`, often as a misguided attempt to pre-size or reset the field collection. The throwing setter aborts the action.","commonSituations":"A script incorrectly assumes `numFields` is a mutable capacity/length; code ported from a different form engine where field count is settable; debugging code that assigns to counters.","solutions":["Use `addField(...)` / `removeField(...)` to change the count, then read `doc.numFields` to observe it.","Replace any `doc.numFields = ...` with a local variable that tracks your own counter.","Gate legacy scripts with a try/catch at the host so the error is non-fatal."],"exampleFix":"// before\ndoc.numFields = doc.numFields + 1;\n\n// after\ndoc.addField('NewField', 'text', [0], 0);\nconsole.log(doc.numFields); // now reflects the new count","handlingStrategy":"validation","validationCode":"const READ_ONLY_DOC_PROPS = new Set(['numFields','numPages' /* ... */]);\nfunction assertsNoReadOnlyWrite(scriptSrc) {\n  for (const p of READ_ONLY_DOC_PROPS) {\n    if (new RegExp(`\\\\bdoc\\\\.${p}\\\\s*=[^=]`).test(scriptSrc)) {\n      throw new Error(`Script writes read-only property doc.${p}`);\n    }\n  }\n}\nassertsNoReadOnlyWrite(myScript);","typeGuard":"function isReadOnlyDocProp(doc, prop) {\n  const desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(doc), prop)\n    || Object.getOwnPropertyDescriptor(doc, prop);\n  return !!desc && !!desc.get && !desc.set;\n}\nisReadOnlyDocProp(doc, 'numFields'); // true","tryCatchPattern":"try {\n  doc.numFields = n;\n} catch (e) {\n  if (/numFields is read-only/.test(e.message)) console.warn(e.message);\n  else throw e;\n}","preventionTips":["Change field count only through `addField`/`removeField`; read `doc.numFields` to observe it.","Lint scripts for assignments to read-only count properties before execution.","Wrap legacy scripts in try/catch at the host dispatch boundary."],"tags":["scripting","acrobat-js-api","doc-object","read-only","fields"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}