gildas-lormeau/SingleFile · error · Error

INDEX_PAGE_NOT_FOUND_ERROR

INDEX_PAGE_NOT_FOUND_ERROR

Error message

Index page not found

What it means

convert() walks the MHTML archive's resources looking for the index page; if none of the resources qualifies as an index and it cannot synthesize a document (createDocument returns null), it throws INDEX_PAGE_NOT_FOUND_ERROR. This happens because an archive is not required to contain an HTML page — browsers also save standalone images or text files in MHTML format.

Source

Thrown at src/lib/mhtml-to-html/convert.js:241

    }
}

function getBackoffDelay(indexAttempt) {
    return Math.min(RETRY_BASE_DELAY * Math.pow(2, indexAttempt), MAX_RETRY_DELAY);
}

function wait(delay) {
    return new Promise(resolve => setTimeout(resolve, delay));
}

function convert({ headers, frames, resources, unfoundResources = new Set(), index, id, anomalies = [] }, { DOMParser, enableScripts, fetchMissingResources } = { DOMParser: globalThis.DOMParser }) {
    let resource = resources[index];
    if (!resource) {
        // an archive does not have to hold a page: a browser saves a standalone image or text file
        // the same way, and presents it as a document built around that single resource
        resource = createDocument(resources);
        if (!resource) {
            throw new Error(INDEX_PAGE_NOT_FOUND_ERROR);
        }
        index = resource.id;
        if (!fetchMissingResources) {
            // reported on a copy rather than pushed into the parse result, so converting the same
            // archive again reports it once again instead of twice
            anomalies = [...anomalies, { type: SYNTHESIZED_INDEX_ANOMALY, id: index }];
        }
    }
    let base = resource.id;
    if (resource.transferEncoding === BASE64_ENCODING) {
        resource.transferEncoding = undefined;
        resource.data = decodeBase64(resource.data, getCharset(resource.contentType));
    }
    // a part is not required to declare a type, and parseDOM falls back to HTML when it does not
    const contentType = resource.contentType ? resource.contentType.split(CONTENT_TYPE_SEPARATOR)[0] : undefined;
    const dom = getResourceDOM(resource, contentType, DOMParser);
    if (!fetchMissingResources) {
        // the rewrite mutates the tree it walks, so the cached one is given up: were the same

View on GitHub (pinned to 517fb7c5cf)

Solutions

  1. Verify the input file is a valid MHTML archive containing an HTML document (open it in a text editor and look for text/html parts)
  2. Re-save the page from the browser as MHTML (single-file or complete-page option)
  3. Handle the INDEX_PAGE_NOT_FOUND_ERROR code in a catch block and fall back to treating the file as a plain attachment rather than a document
  4. If processing user uploads, validate the MIME type/content before invoking convert()

Example fix

// before
const result = convert(mhtmlBuffer);
// after
let result;
try {
  result = convert(mhtmlBuffer);
} catch (e) {
  if (e.code === "INDEX_PAGE_NOT_FOUND_ERROR") result = null; // not a page archive
  else throw e;
}
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeMhtml(buf) {
  const head = buf.slice(0, 512).toString("latin1");
  return head.includes("MIME-Version") && head.includes("multipart/related");
}
if (!looksLikeMhtml(mhtmlBuffer)) throw new Error("Input is not a valid MHTML archive");

Type guard

function hasIndexResource(resources) {
  return Array.isArray(resources) && resources.some(r => r && typeof r.id !== "undefined");
}

Try / catch

try {
  const result = convert(buffer);
} catch (e) {
  if (e.code === "INDEX_PAGE_NOT_FOUND_ERROR") {
    // archive holds no HTML page (e.g. saved image); handle as attachment
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an MHTML file whose resources contain no HTML document and whose single resource cannot be turned into a document (e.g., a binary/image-only archive where createDocument fails, or an empty/corrupt resource list).

Common situations: Converting an MHTML file saved from a direct image download link; a truncated or corrupt .mhtml file with an empty or malformed resource table; feeding a non-MHTML file (plain text, partial download) to the converter.


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