vercel-labs/skills · error · ArchiveValidationError
Archive extracts to more than ${limits.extractMaxBytes} byte
Error message
Archive extracts to more than ${limits.extractMaxBytes} bytes. Set SKILLS_EXTRACT_MAX_BYTES to override. What it means
incrementEntry accumulates each entry's size into state.bytes and throws ArchiveValidationError when the total exceeds limits.extractMaxBytes. It prevents an archive from expanding to an unbounded number of bytes on disk (the classic decompression-bomb scenario). Override the cap with SKILLS_EXTRACT_MAX_BYTES.
Source
Thrown at src/download-source.ts:74
function validateArchivePath(path: string): string | null {
const normalized = path.replace(/\\/g, '/').replace(/^\.\//, '');
if (!normalized || normalized.endsWith('/')) return normalized;
if (normalized.startsWith('/') || /^[a-zA-Z]:\//.test(normalized)) return null;
if (normalized.split('/').includes('..')) return null;
return normalized;
}
function incrementEntry(state: ExtractState, size: number, limits: DownloadLimits): void {
state.entries += 1;
if (state.entries > limits.extractMaxFiles) {
throw new ArchiveValidationError(
`Archive contains too many files (${state.entries}). Maximum is ${limits.extractMaxFiles}. Set SKILLS_EXTRACT_MAX_FILES to override.`
);
}
state.bytes += size;
if (state.bytes > limits.extractMaxBytes) {
throw new ArchiveValidationError(
`Archive extracts to more than ${limits.extractMaxBytes} bytes. Set SKILLS_EXTRACT_MAX_BYTES to override.`
);
}
}
async function downloadToFile(
url: string,
targetFile: string,
limits: DownloadLimits
): Promise<void> {
const response = await fetch(url, {
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
redirect: 'follow',
});
if (!response.ok) {
throw new Error(`Download failed with HTTP ${response.status}`);
}View on GitHub (pinned to 435076e789)
Solutions
- Check the archive's uncompressed size first: unzip -l file.zip
- If legitimate, raise the budget: SKILLS_EXTRACT_MAX_BYTES=1073741824 skills add <source>
- Slim the archive (remove large assets, .git, node_modules) and re-package
- For large content, install from a git repo or local directory instead of a zip
Example fix
# before skills add ./big-skills.zip # extracts to more than max bytes # after SKILLS_EXTRACT_MAX_BYTES=536870912 skills add ./big-skills.zip
Defensive patterns
Strategy: validation
Validate before calling
// Sum declared uncompressed sizes before extracting
import { execFileSync } from 'node:child_process';
function zipUncompressedBytes(path: string): number {
const out = execFileSync('unzip', ['-l', path], { encoding: 'utf8' });
const m = out.match(/\s([0-9,]+)\s+\d+ files?/);
return m ? Number(m[1].replace(/,/g, '')) : -1;
} Type guard
null
Try / catch
try {
await extractArchive(file, limits);
} catch (err) {
if (err instanceof ArchiveValidationError && err.message.includes('extractMaxBytes')) {
// abort: archive expands beyond budget — reject rather than raise
} else throw err;
} Prevention
- Keep large binaries out of skill archives
- Set SKILLS_EXTRACT_MAX_BYTES explicitly in automation so failures are deterministic
When it happens
Trigger: Extracting an archive whose declared uncompressed total exceeds the configured byte budget — highly compressed payloads (zip bombs) or legitimately large bundles such as binaries, images, or model files inside a skill archive.
Common situations: Skill archives that bundle large assets, CI environments with tight limits, or a deliberately malicious archive downloaded from an untrusted URL.
Related errors
- Archive contains too many files (${state.entries}). Maximum
- Download is larger than ${limits.downloadMaxBytes} bytes. Se
- Archive exceeds maximum unpacked size
- Invalid zip archive: ${label} is out of bounds
- Invalid zip archive: ${label} exceeds the safe integer range
AI-assisted analysis of vercel-labs/skills@435076e789 (2026-08-28).
Data as JSON: /api/errors/c8011c1cdb375235.
Report an issue: GitHub.