TryGhost/Ghost · warning · ThemeArchiveExtractionError

too_large

too_large

Error message

This theme archive is too large to open in the browser editor. Extracted files must stay under ${getThemeArchiveSizeLabel(THEME_EDITOR_ARCHIVE_LIMITS.maxExtractedBytes)}.

What it means

Thrown by trackExtractedBytes during extraction when the running total of extracted bytes exceeds THEME_EDITOR_ARCHIVE_LIMITS.maxExtractedBytes (32 MiB). This guards against zip-bomb-style or asset-heavy archives that would exhaust browser memory: each extracted file (text-encoded for editable files, raw bytes for binary) is added to a running total, and the limit is on the DECOMPRESSED size, not the archive size. Thrown as ThemeArchiveExtractionError with reason 'too_large'.

Source

Thrown at apps/admin/src/settings/app/components/settings/site/theme/theme-editor-utils.ts:234

        throw new ThemeArchiveExtractionError('invalid_archive', invalidArchiveMessage);
    }
};

const getNormalizedArchivePath = (path: string) => {
    const normalizedPath = normaliseRelativePath(path);

    if (!normalizedPath || normalizedPath !== path) {
        throw new ThemeArchiveExtractionError('invalid_archive', invalidArchiveMessage);
    }

    return normalizedPath;
};

const trackExtractedBytes = (totalBytes: number, fileBytes: number) => {
    const nextTotal = totalBytes + fileBytes;

    if (nextTotal > THEME_EDITOR_ARCHIVE_LIMITS.maxExtractedBytes) {
        throw new ThemeArchiveExtractionError(
            'too_large',
            `This theme archive is too large to open in the browser editor. Extracted files must stay under ${getThemeArchiveSizeLabel(THEME_EDITOR_ARCHIVE_LIMITS.maxExtractedBytes)}.`
        );
    }

    return nextTotal;
};

export const extractThemeArchive = async (arrayBuffer: ArrayBuffer): Promise<ThemeEditorSnapshot> => {
    const zip = await loadThemeArchive(arrayBuffer);
    const entries = collectArchiveEntries(zip);

    assertThemeArchiveLimits(entries);

    const rootPrefix = detectCommonRoot(entries.map(([path]) => path));
    const files: Record<string, ThemeEditorFile> = {};
    const textEncoder = new TextEncoder();
    let extractedBytes = 0;

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Reduce the extracted footprint: optimise/compress images, remove unused binary assets, and re-zip so the decompressed total stays under 32 MiB.
  2. Pre-check by summing uncompressed sizes locally (unzip -l shows uncompressed bytes per entry) before uploading.
  3. If the theme legitimately needs more, raise THEME_EDITOR_ARCHIVE_LIMITS.maxExtractedBytes, but reconsider whether the in-browser editor is the right tool — use server-side theme upload instead.
  4. Strip large media from the edit-time archive and add them back through Ghost's media management.

Example fix

// before — extraction throws ThemeArchiveExtractionError mid-flow
const snapshot = await extractThemeArchive(arrayBuffer);

// after — catch and branch on the typed reason
import {ThemeArchiveExtractionError} from './theme-editor-utils';
try {
    const snapshot = await extractThemeArchive(arrayBuffer);
} catch (e) {
    if (e instanceof ThemeArchiveExtractionError && e.reason === 'too_large') {
        setUploadError(e.message); // 'This theme archive is too large ...'
        return;
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// The limit is on DECOMPRESSED bytes, so you can't fully pre-validate from archive size,
// but you can reject obviously oversized archives early as a coarse guard.
const COARSE_LIMIT = 64 * 1024 * 1024; // be generous vs the 32 MiB extracted cap
if (arrayBuffer.byteLength > COARSE_LIMIT) {
    setUploadError('Archive is too large for the browser editor.');
}

Type guard

import {ThemeArchiveExtractionError} from './theme-editor-utils';
function isTooLarge(e: unknown): e is ThemeArchiveExtractionError {
    return e instanceof ThemeArchiveExtractionError && e.reason === 'too_large';
}

Try / catch

import {extractThemeArchive, ThemeArchiveExtractionError} from './theme-editor-utils';
try {
    const snapshot = await extractThemeArchive(arrayBuffer);
} catch (e) {
    if (e instanceof ThemeArchiveExtractionError && e.reason === 'too_large') {
        setUploadError(e.message);
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: extractThemeArchive accumulates > 32 MiB across extracted entries. Triggers: a theme with large uncompressed images/fonts/videos, a highly compressible archive (zip bomb), or many binary assets whose summed byteLength crosses 32 MiB even if the .zip itself is small.

Common situations: Theme bundles full-resolution hero images, woff2 fonts, or video files; developer included raw (unoptimised) assets; malicious or pathological archive with high compression ratio; bundled sample media.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/30be764f488ba02a. Report an issue: GitHub.