nexu-io/open-design · error · Error
zip does not contain an HTML file
Error message
zip does not contain an HTML file
What it means
Thrown by `importClaudeDesignZip` after collecting files if `chooseEntryFile` returns null — meaning no entry path matched `/\.html?$/i`. Claude Design exports are HTML-based and the importer requires at least one `.html` or `.htm` file to select as the entry point.
Source
Thrown at apps/daemon/src/design/claude-design-import.ts:58
// streaming/data-descriptor zips (it can read 0 even when the payload
// carries real data). The inflate cap and the post-decode size checks below
// are authoritative.
const body = readEntryBody(zip, entry);
if (body.length > MAX_FILE_BYTES) {
throw new Error(`zip file too large: ${relPath}`);
}
if (entry.uncompressedSize > 0 && body.length !== entry.uncompressedSize) {
throw new Error(`zip entry size mismatch: ${relPath}`);
}
totalBytes += body.length;
if (totalBytes > MAX_TOTAL_BYTES) throw new Error('zip is too large');
files.push({ path: relPath, body: normalizeImportedClaudeDesignFile(relPath, body) });
}
if (files.length === 0) throw new Error('zip contains no files');
const entryFile = chooseEntryFile(files.map((f) => f.path));
if (!entryFile) throw new Error('zip does not contain an HTML file');
const dirCreates = new Map<string, Promise<string | undefined>>();
const ensureDir = (dir: string) => {
let pending = dirCreates.get(dir);
if (!pending) {
pending = mkdir(dir, { recursive: true });
dirCreates.set(dir, pending);
}
return pending;
};
await mkdir(projectDir, { recursive: true });
await Promise.all(files.map(async (f) => {
const target = safeJoin(projectDir, f.path);
await ensureDir(path.dirname(target));
await writeFile(target, f.body);
}));
View on GitHub (pinned to 5be4028344)
Solutions
- Ensure the archive includes at least one `.html`/`.htm` file (typically `index.html`).
- Re-export from Claude Design so the HTML entry is included.
- Confirm you are uploading a Claude Design HTML export and not a different archive type.
Defensive patterns
Strategy: validation
Validate before calling
const fileEntries = entries.filter((e) => !e.isDirectory).map((e) => e.name);
const hasHtml = fileEntries.some((p) => /\.html?$/i.test(p));
if (!hasHtml) {
throw new Error('archive contains no .html/.htm entry file');
} Try / catch
try {
await importClaudeDesignZip(zipPath, projectDir);
} catch (err) {
if (err instanceof Error && err.message === 'zip does not contain an HTML file') {
// ensure the archive includes index.html and re-upload
}
throw err;
} Prevention
- Ensure the archive includes at least one `.html`/`.htm` file (typically `index.html`).
- Confirm you are uploading a Claude Design HTML export, not an unrelated archive.
- Re-export from Claude Design if the HTML entry is missing.
When it happens
Trigger: An archive that contains files (passes the empty-archive check) but none of them have an `.html` or `.htm` extension — e.g. only `.css`, `.js`, `.png`, or extensionless files.
Common situations: Zipping the wrong directory (assets folder instead of the build output). An export pipeline that emits `index` without the `.html` extension. A non-Claude-Design archive uploaded through the Claude Design import path.
Related errors
- zip entry size mismatch: ${relPath}
- zip contains no files
- invalid zip central directory
- invalid zip central directory entry
- zip entry exceeds archive: ${entry.name}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/24366833da3f7d50.
Report an issue: GitHub.