TryGhost/Ghost · warning · ThemeArchiveExtractionError

too_many_files

too_many_files

Error message

This theme archive contains too many files for the browser editor (${entries.length}/${THEME_EDITOR_ARCHIVE_LIMITS.maxFiles}).

What it means

Thrown by assertThemeArchiveLimits in theme-editor-utils when a uploaded theme .zip contains more than THEME_EDITOR_ARCHIVE_LIMITS.maxFiles (1000) non-directory entries. It is a browser-side guard: the in-browser theme editor (JSZip-based) is not designed to ingest huge archives (e.g. ones accidentally bundling node_modules or generated asset variants), so extraction is aborted before memory/time becomes a problem. Thrown as ThemeArchiveExtractionError with reason 'too_many_files'.

Source

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

    return `${megabytes.toFixed(1)} MB`;
};

const collectArchiveEntries = (zip: JSZip) => {
    const entries: Array<[string, JSZip.JSZipObject]> = [];

    zip.forEach((relativePath, entry) => {
        if (!entry.dir) {
            entries.push([relativePath, entry]);
        }
    });

    return entries;
};

const assertThemeArchiveLimits = (entries: Array<[string, JSZip.JSZipObject]>) => {
    if (entries.length > THEME_EDITOR_ARCHIVE_LIMITS.maxFiles) {
        throw new ThemeArchiveExtractionError(
            'too_many_files',
            `This theme archive contains too many files for the browser editor (${entries.length}/${THEME_EDITOR_ARCHIVE_LIMITS.maxFiles}).`
        );
    }
};

const loadThemeArchive = async (arrayBuffer: ArrayBuffer) => {
    try {
        return await JSZip.loadAsync(arrayBuffer);
    } catch {
        throw new ThemeArchiveExtractionError('invalid_archive', invalidArchiveMessage);
    }
};

const readThemeBinaryFile = async (entry: JSZip.JSZipObject) => {
    try {
        return await entry.async('uint8array');
    } catch {

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Re-zip the theme excluding node_modules, .git, and large generated asset directories so it contains only the theme files Ghost needs.
  2. Verify the file count locally before upload: unzip -l theme.zip | tail -1 (or JSZip inspection) to confirm it's under 1000 entries.
  3. If the limit is genuinely too low for a legitimate theme, raise THEME_EDITOR_ARCHIVE_LIMITS.maxFiles in code, but treat that as a last resort — the browser editor isn't meant for arbitrarily large archives.
  4. Prefer uploading the theme via the Ghost Admin upload (server-side extraction) instead of the in-browser editor for large themes.

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_many_files') {
        setUploadError(e.message); // 'This theme archive contains too many files ...'
        return;
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: extractThemeArchive is called with an ArrayBuffer whose zip contains > 1000 file entries (directories excluded by collectArchiveEntries). Common: a theme zip that included node_modules, a .git directory, generated/image-sprite folders, or multiple bundled themes.

Common situations: Theme developer ran a build that emitted thousands of files; user zipped the whole project folder instead of the dist output; a downloaded third-party theme ships heavy asset directories; CI artifact accidentally includes dev dependencies.

Related errors


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