mozilla/pdf.js · error · Error

doc.info.${prop} is read-only

Error message

doc.info.${prop} is read-only

What it means

`doc.info` is a `Proxy` (handler `InfoProxyHandler` in doc.js) over the document's Info dictionary: title, author, authors, subject, keywords, creator, producer, creationdate, moddate, trapped. Reads are case-insensitive; the `set` trap throws `Error("doc.info.${prop} is read-only")` for ANY written property name, interpolating the key. So even writing an unknown key throws.

Source

Thrown at src/scripting_api/doc.js:30

 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { makeArr, makeMap, serializeError } from "./app_utils.js";
import { createMap } from "./common.js";
import { PDFObject } from "./pdf_object.js";
import { PrintParams } from "./print_params.js";
import { ZoomType } from "./constants.js";

const DOC_EXTERNAL = false;

class InfoProxyHandler {
  static get(obj, prop) {
    return obj[prop.toLowerCase()];
  }

  static set(obj, prop, value) {
    throw new Error(`doc.info.${prop} is read-only`);
  }
}

class Doc extends PDFObject {
  #pageActions = null;

  #otherPageActions = null;

  constructor(data) {
    super(data);

    // In a script doc === this.
    // So adding a property to the doc means adding it to this
    this._expandos = globalThis;

    this._baseURL = data.baseURL || "";
    this._calculate = true;
    this._delay = false;

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Do not assign to `doc.info.*`; treat it as read-only metadata.
  2. Set title/author/subject/keywords in the PDF's Info dictionary at authoring time and re-export.
  3. Wrap the assignment in try/catch if you must run untrusted/portable PDFs unchanged.

Example fix

// before
doc.info.title = "Annual Report";
// after
// info is read-only in pdf.js; set the title in the PDF's Info dictionary at creation, then read doc.info.title
Defensive patterns

Strategy: try-catch

Validate before calling

// doc.info is a Proxy whose set trap always throws; there is no // writable sub-property, so do not attempt any assignment to it.
// Read-only access is safe: const title = doc.info.title;

Type guard

// Every key on doc.info is read-only -> the only safe operation is read.
const isInfoWriteSafe = () => false;

Try / catch

try {
  doc.info[prop] = value;
} catch (e) {
  if (/doc\.info\..*is read-only/.test(e.message)) { /* expected; ignore */ }
  else { throw e; }
}

Prevention

When it happens

Trigger: Any sandboxed assignment to an info sub-property: `doc.info.Title = "x"`, `doc.info["author"] = "y"`, or `doc.info.custom = 1` (custom also throws because the trap is unconditional).

Common situations: Scripts ported from old Acrobat versions where info was mutable; forms that try to write the logged-in user into `doc.info.author` on save; metadata-stamping scripts.

Related errors


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