can1357/oh-my-pi · error · ArchiveError
Invalid ZIP archive: symlink has no payload
Error message
Invalid ZIP archive: symlink has no payload
What it means
Thrown when a central-directory entry is detected as a symlink but its storage type is not a regular member payload, so the library cannot read the symlink target bytes to validate them. It refuses to construct an entry with an unverifiable target.
Source
Thrown at packages/utils/src/ar/zip.ts:554
};
parsed.push({ entry, isSymlink });
assertEntryCount(parsed.length, options.limits);
}
offset = end;
}
return parsed;
}
async function readZipImpl(source: ByteSource, options: FormatReadOptions): Promise<ArchiveIndexEntry[]> {
const info = await readCentralDirectoryInfo(source, options.limits);
if (info.size === 0) return [];
const directory = await source.read(info.offset, info.offset + info.size);
if (directory.byteLength !== info.size) throw new ArchiveError("Invalid ZIP archive: truncated central directory");
const parsed = parseCentralDirectory(source, directory, info, options);
for (const item of parsed) {
if (!item.isSymlink) continue;
assertArchivePathBytes(item.entry.size, "symlink target", options.limits.maxPathBytes);
if (item.entry.storage?.type !== "member") throw new ArchiveError("Invalid ZIP archive: symlink has no payload");
const bytes = await item.entry.storage.source.read(item.entry.size, item.entry.path);
const target = UTF8_DECODER.decode(bytes);
assertArchivePathString(target, "symlink target", options.limits.maxPathBytes);
const portable = target.replace(/\\/g, "/");
const absolute = path.posix.isAbsolute(portable) || /^[A-Za-z]:/.test(portable) || portable.includes("\0");
const targetPath = absolute
? undefined
: normalizeArchiveLookupPath(path.posix.join(path.posix.dirname(item.entry.path), portable));
item.entry.size = 0;
item.entry.storage = {
type: "link",
targetPath: targetPath === undefined ? portable : targetPath,
resolveTarget: targetPath !== undefined,
};
}
return parsed.map(item => item.entry);
}
View on GitHub (pinned to 9690622007)
Solutions
- Recreate the archive with a zip tool that stores symlinks correctly (e.g. `zip -ry archive.zip dir` preserves symlinks)
- Inspect the archive with `unzip -v` / 7-Zip to find the malformed symlink entry and repair or drop it
- If you only need regular files, filter out symlinks before/while reading if the API allows, or extract with a tolerant tool first
Example fix
// before: zipping with a tool that breaks symlinks await $`zip -r app.zip app`; // after: preserve symlinks recursively await $`zip -ry app.zip app`;
Defensive patterns
Strategy: try-catch
Validate before calling
const entries = await listZip(file); // if listing API available
const bad = entries.filter(e => e.isSymlink && (e.size === 0 || e.storageType !== 'member'));
if (bad.length) throw new Error(`malformed symlinks: ${bad.map(b => b.path).join(', ')}`); Try / catch
try {
return await readZip(file);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('symlink has no payload')) {
logger.warn('skipping archive with malformed symlink entries', { path: file.name });
return null;
}
throw err;
} Prevention
- Create archives with symlink-preserving flags (zip -ry)
- Avoid tar-to-zip converters that drop symlink payloads
- Inspect archives containing symlinks with unzip -v before automated processing
When it happens
Trigger: Reading a ZIP containing a symlink entry (external attributes mark it as a symlink) whose storage is missing or of a non-member type — typically a corrupt entry, a directory placeholder, or a zero-size/dangling symlink record.
Common situations: ZIPs of Unix directory trees created by tools that mishandle symlinks (some tar-to-zip converters, misconfigured CI packaging); archives truncated or patched so the symlink's data offset no longer resolves.
Related errors
- Invalid ZIP archive: truncated central-directory entry
- Invalid ARJ archive: truncated ${what}
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ basic header size
- Invalid ARJ basic header CRC32
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f7f8d1f6dbf2bd62.
Report an issue: GitHub.