gildas-lormeau/SingleFile · error · Error

First argument to Readability constructor should be a docume

Error message

First argument to Readability constructor should be a document object.

What it means

The Readability constructor requires a parsed DOM Document object (something with a .documentElement property) as its first argument. It throws this error when given null/undefined or any non-document value — most commonly a raw HTML string, which older API versions and tutorials mistakenly showed as acceptable.

Source

Thrown at src/lib/readability/Readability.js:33

 */

/*
 * This code is heavily based on Arc90's readability.js (1.7.1) script
 * available at: http://code.google.com/p/arc90labs-readability
 */

/**
 * Public constructor.
 * @param {HTMLDocument} doc     The document to parse.
 * @param {Object}       options The options object.
 */
function Readability(doc, options) {
  // In some older versions, people passed a URI as the first argument. Cope:
  if (options && options.documentElement) {
    doc = options;
    options = arguments[2];
  } else if (!doc || !doc.documentElement) {
    throw new Error(
      "First argument to Readability constructor should be a document object."
    );
  }
  options = options || {};

  this._doc = doc;
  this._docJSDOMParser = this._doc.firstChild.__JSDOMParser__;
  this._articleTitle = null;
  this._articleByline = null;
  this._articleDir = null;
  this._articleSiteName = null;
  this._attempts = [];
  this._metadata = {};

  // Configurable options
  this._debug = !!options.debug;
  this._maxElemsToParse =
    options.maxElemsToParse || this.DEFAULT_MAX_ELEMS_TO_PARSE;

View on GitHub (pinned to 517fb7c5cf)

Solutions

  1. Parse the HTML string into a document first: new JSDOM(html).window.document or new DOMParser().parseFromString(html, "text/html")
  2. If using JSDOM, pass jsdom.window.document, not the JSDOM instance itself
  3. Check that the fetch/DOM parse step actually produced a document before constructing Readability
  4. If you intentionally passed a URI in options, ensure options.documentElement handling matches the current library version

Example fix

// before
const article = new Readability(htmlString).parse();
// after
const doc = new JSDOM(htmlString).window.document;
const article = new Readability(doc).parse();
Defensive patterns

Strategy: type-guard

Validate before calling

if (!doc || typeof doc !== "object" || !doc.documentElement) {
  throw new Error("Readability requires a Document object, not a string");
}

Type guard

function isDocument(obj) {
  return obj != null && typeof obj === "object" && obj.nodeType === 9 && !!obj.documentElement;
}
// usage: if (!isDocument(input)) input = new JSDOM(html).window.document;

Try / catch

let doc = htmlString ? new JSDOM(htmlString).window.document : maybeDoc;
if (!isDocument(doc)) throw new Error("Could not build a DOM document for Readability");
try {
  const article = new Readability(doc).parse();
} catch (e) {
  if (e.message.includes("First argument to Readability")) throw new Error("Input HTML failed to parse into a document");
  throw e;
}

Prevention

When it happens

Trigger: new Readability(htmlString) instead of a DOM document; passing null/undefined because the page fetch or DOMParser.parseFromString returned an error document or nothing; passing a JSDOM instance instead of its window.document.

Common situations: Following outdated examples that passed an HTML string or URI; mixing up JSDOM object with its .window.document; DOMParser failing silently in non-browser environments; response body not parsed into a document before constructing.

Related errors


AI-assisted analysis of gildas-lormeau/SingleFile@517fb7c5cf (2026-09-01). Data as JSON: /api/errors/0641b20d7143f432. Report an issue: GitHub.