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

  1. Remove password protection from the archive (open it with the password and re-save it unencrypted) before editing pages in the editor.
  2. Decrypt the archive programmatically first (e.g. re-zip the entries without encryption) and feed the resulting unencrypted bytes to the editor.
  3. Ask users to import an unencrypted copy of the document; surface this error in UI with guidance that encrypted archives are read-only.
  4. 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

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.