{"record":{"id":"292128b97b70d136","repo":"mozilla/pdf.js","slug":"doc-mousey-is-read-only","errorCode":null,"errorMessage":"doc.mouseY is read-only","messagePattern":"doc\\.mouseY is read-only","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/scripting_api/doc.js","lineNumber":502,"sourceCode":"\n  set modDate(_) {\n    throw new Error(\"doc.modDate is read-only\");\n  }\n\n  get mouseX() {\n    return 0;\n  }\n\n  set mouseX(_) {\n    throw new Error(\"doc.mouseX is read-only\");\n  }\n\n  get mouseY() {\n    return 0;\n  }\n\n  set mouseY(_) {\n    throw new Error(\"doc.mouseY is read-only\");\n  }\n\n  get noautocomplete() {\n    return this._noautocomplete;\n  }\n\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","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/scripting_api/doc.js#L484-L520","documentation":"`Doc.mouseY` is the read-only counterpart to mouseX, returning the cursor's Y coordinate (points) from the page's top-left corner. PDF.js hard-codes it to 0 because the browser-rendered viewer does not push live cursor coordinates into the sandboxed scripting engine. The setter throws `doc.mouseY is read-only` to enforce the Acrobat spec contract that cursor position is observable, not settable.","triggerScenarios":"A document script assigns to `doc.mouseY` (e.g. `doc.mouseY = someValue;`) inside any script event (Page/Open, MouseUp, Calculate). The throwing setter fires on that assignment line.","commonSituations":"Legacy AcroJS scripts attempting to record or override cursor position; scripts auto-generated by form designers that probe-set every property; tutorials copied from the Acrobat SDK that demonstrate unsupported writes.","solutions":["Delete the assignment; treat mouseY as read-only input only (`var y = doc.mouseY;`).","Use the `event` object fields (`event.y`, `event.targetY`) for the coordinate at the action that triggered the script.","Run untrusted/legacy scripts through a try/catch boundary so a read-only write is logged and skipped rather than fatal."],"exampleFix":"// before\ndoc.mouseY = doc.mouseY + 10;\n\n// after\nvar y = doc.mouseY; // 0 in PDF.js; not writable","handlingStrategy":"try-catch","validationCode":"const READ_ONLY_DOC_PROPS = new Set(['mouseX','mouseY' /* ... */]);\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, 'mouseY'); // true","tryCatchPattern":"try {\n  doc.mouseY = value; // legacy write\n} catch (e) {\n  if (/mouseY is read-only/.test(e.message)) {\n    console.warn('Ignored read-only write:', e.message);\n  } else { throw e; }\n}","preventionTips":["Read cursor coordinates from the `event` object in action handlers rather than writing `doc.mouseX/mouseY`.","Keep a static list of read-only Doc properties and lint scripts before running them.","Isolate untrusted scripts in try/catch so a read-only assignment logs and continues."],"tags":["scripting","acrobat-js-api","doc-object","read-only","mouse"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}