parallax/jsPDF · error · Error

putCatalogCallback: Root missing.

Error message

putCatalogCallback: Root missing.

What it means

Thrown by the putCatalogCallback during PDF output when scope.internal.acroformPlugin.acroFormDictionaryRoot is undefined. This callback writes the /AcroForm reference into the document catalog, so a missing root means the AcroForm plugin state was not initialized or was lost before output. It is an internal-state-consistency error, not a normal user error.

Source

Thrown at src/modules/acroform.js:534

};

// Callbacks

var putCatalogCallback = function(scope) {
  // Put reference to AcroForm to DocumentCatalog
  if (
    typeof scope.internal.acroformPlugin.acroFormDictionaryRoot !== "undefined"
  ) {
    // for safety, shouldn't normally be the case
    scope.internal.write(
      "/AcroForm " +
        scope.internal.acroformPlugin.acroFormDictionaryRoot.objId +
        " " +
        0 +
        " R"
    );
  } else {
    throw new Error("putCatalogCallback: Root missing.");
  }
};

/**
 * Adds /Acroform X 0 R to Document Catalog, and creates the AcroForm
 * Dictionary
 */
var AcroFormDictionaryCallback = function(scope) {
  // Remove event
  scope.internal.events.unsubscribe(
    scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID
  );
  delete scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID;
  scope.internal.acroformPlugin.printedOut = true;
};

/**
 * Creates the single Fields and writes them into the Document

View on GitHub (pinned to a3930ce03a)

Solutions

  1. Ensure at least one AcroForm field is added via doc.addField(...) before output so initializeAcroForm runs.
  2. Verify scope.internal.acroformPlugin and its acroFormDictionaryRoot are defined before output in custom workflows.
  3. If you do not need forms, avoid loading the acroform module; if you do, follow the documented field-add sequence.
  4. Wrap doc.output() in try/catch to surface the state error gracefully.

Example fix

// before
doc.output('arraybuffer'); // no field added -> putCatalogCallback throws

// after
var field = new doc.AcroFormField();
field.FT = '/Tx';
field.T = 'Name';
field.Rect = [10, 10, 100, 30];
doc.addField(field);
doc.output('arraybuffer');
Defensive patterns

Strategy: try-catch

Validate before calling

function ensureAcroFormReady(doc) {
  var p = doc.internal && doc.internal.acroformPlugin;
  if (!p || typeof p.acroFormDictionaryRoot === 'undefined') {
    throw new Error('AcroForm plugin not initialized; add at least one field before output');
  }
}
ensureAcroFormReady(doc);

Type guard

function hasAcroFormRoot(doc) {
  return !!(doc.internal && doc.internal.acroformPlugin &&
            doc.internal.acroformPlugin.acroFormDictionaryRoot);
}

Try / catch

try {
  return doc.output('arraybuffer');
} catch (e) {
  if (/putCatalogCallback: Root missing/.test(e.message)) {
    throw new Error('No AcroForm fields were added before output');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling doc.output() / doc.save() when the AcroForm plugin's dictionary root was never created (e.g. the catalog callback fires but initializeAcroForm did not run), or when internal state was reset between adding fields and output.

Common situations: A bug in field initialization ordering; reusing a jsPDF instance after a partial reset; an AcroForm module version mismatch; calling output on a document where addField failed silently.

Related errors


AI-assisted analysis of parallax/jsPDF@a3930ce03a (2026-08-13). Data as JSON: /api/errors/50c7ec9202476fd1. Report an issue: GitHub.