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 sameView on GitHub (pinned to 517fb7c5cf)
Solutions
- 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)
- Re-save the page from the browser as MHTML (single-file or complete-page option)
- 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
- 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
- Validate uploads are real MHTML (multipart/related) before converting
- Re-save corrupt/truncated archives from the browser
- Treat single-resource archives (images/text) as a separate code path
- Unit-test conversion with page, image-only, and empty archives
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.