gildas-lormeau/SingleFile · error · Error
Saving encrypted multi-page archives is not supported yet.
Error message
Saving encrypted multi-page archives is not supported yet.
What it means
The background UI editor's saveArchive() refuses to persist an archive when zip.js reports any entry as encrypted. Writing modified pages back into an encrypted multi-page archive is not implemented (it would require decrypt/re-encrypt handling), so the code closes the ZipReader and throws this explicit feature-gap Error before any data is modified.
Source
Thrown at src/ui/bg/ui-editor.js:528
editorElement = previousEditorElement.cloneNode(true);
editorElement.onload = () => {
editorElement.onload = null;
browser.runtime.sendMessage({ method: "editor.getTabData" });
};
previousEditorElement.replaceWith(editorElement);
});
async function saveArchive(message) {
const options = tabData.options;
const manifest = message.manifest || {};
const manifestPages = manifest.pages || [];
const aliases = manifest.aliases || {};
const originalData = new Uint8Array(message.archiveContent);
const zipReader = new zip.ZipReader(new zip.Uint8ArrayReader(originalData));
const entries = await zipReader.getEntries();
if (entries.some(entry => entry.encrypted)) {
await zipReader.close();
throw new Error("Saving encrypted multi-page archives is not supported yet.");
}
const entryMap = new Map(entries.map(entry => [entry.filename, entry]));
const modifiedPages = new Map(message.pages.map(page => [page.path, page]));
const pages = manifestPages.map(page => {
const modifiedPage = modifiedPages.get(page.path);
return {
url: page.url,
originalUrls: page.originalUrls,
title: modifiedPage ? modifiedPage.title : page.title,
getData: () => getPageData(page.path)
};
});
const zipScript = await (await fetch("/lib/single-file-zip.min.js")).text();
const selfExtractingArchive = tabData.selfExtractingArchive !== undefined ?
tabData.selfExtractingArchive :
!(originalData[0] == 0x50 && originalData[1] == 0x4B);
const data = await zip.createPagesArchive(pages, {
selfExtractingArchive,View on GitHub (pinned to 517fb7c5cf)
Solutions
- Remove password protection from the archive (open it with the password and re-save it unencrypted) before editing pages in the editor.
- Decrypt the archive programmatically first (e.g. re-zip the entries without encryption) and feed the resulting unencrypted bytes to the editor.
- Ask users to import an unencrypted copy of the document; surface this error in UI with guidance that encrypted archives are read-only.
- Track upstream support for encrypted multi-page archive saving and upgrade when available.
Example fix
// before // editing a password-protected archive then saving -> throws const pages = await editor.save(encryptedArchiveBytes); // after const decryptedBytes = await unzipWithoutPassword(encryptedArchiveBytes, userPassword); const plainZip = await rezipUnencrypted(decryptedBytes); const pages = await editor.save(plainZip);
Defensive patterns
Strategy: validation
Validate before calling
import * as zip from '@zip.js/zip.js';
export async function assertNotEncrypted(uint8) {
const reader = new zip.ZipReader(new zip.Uint8ArrayReader(new Uint8Array(uint8)));
try {
const entries = await reader.getEntries();
if (entries.some(e => e.encrypted)) {
throw new Error('Archive is password-protected; decrypt before saving');
}
} finally { await reader.close(); }
} Type guard
function isEncryptedArchiveError(e) {
return e instanceof Error && e.message.includes('encrypted multi-page archives');
} Try / catch
try {
await editor.saveArchive(message);
} catch (e) {
if (isEncryptedArchiveError(e)) {
showUserMessage('This document is password-protected. Remove the password before saving edits.');
return; // do not retry
}
throw e;
} Prevention
- Detect entry.encrypted when opening an archive and switch the UI to read-only mode before edits.
- Prompt for the archive password at import time and re-zip entries unencrypted for editing.
- Reject password-protected uploads at ingestion rather than at save time.
- Keep editors and zip.js updated in case encrypted-save support lands upstream.
When it happens
Trigger: saveArchive() receives message.archiveContent whose zip entries list contains at least one entry with entry.encrypted === true while the caller attempts to save modified pages into it via the editor save flow.
Common situations: User opens a password-protected ZIP-based document (e.g. an encrypted CBZ/ODF/zip archive) in the editor, edits pages, then hits save; archives produced by tools that encrypt entries by default; user supplied the wrong (unencrypted) copy but some entries remain encrypted.
AI-assisted analysis of gildas-lormeau/SingleFile@517fb7c5cf (2026-09-01).
Data as JSON: /api/errors/5ac77960fe25bf49.
Report an issue: GitHub.