can1357/oh-my-pi · error · ArchiveError
Invalid CPIO archive: symlink '${recordPath}' has an invalid
Error message
Invalid CPIO archive: symlink '${recordPath}' has an invalid UTF-8 target What it means
When a symlink entry is indexed, makeLinkTarget decodes the link-target bytes and throws ArchiveError naming the offending record path if the bytes are not valid UTF-8 (fatal decoding fails) or contain an embedded NUL. The library requires symlink targets to be well-formed UTF-8 text without NULs so it can represent them as string targetPath values.
Source
Thrown at packages/utils/src/ar/cpio.ts:206
function decodeUtf8(bytes: Uint8Array): string | undefined {
try {
return UTF8_FATAL_DECODER.decode(bytes);
} catch {
return undefined;
}
}
function validateZeroPadding(bytes: Uint8Array, start: number, end: number, what: string): void {
for (let offset = start; offset < end; offset++) {
if (bytes[offset] !== 0) throw new ArchiveError(`Invalid CPIO archive: non-zero ${what} padding`);
}
}
function makeLinkTarget(recordPath: string, targetBytes: Uint8Array, maxPathBytes: number): LinkTarget {
assertArchivePathBytes(targetBytes.byteLength, "link target", maxPathBytes);
const rawTarget = decodeUtf8(targetBytes);
if (rawTarget === undefined || rawTarget.includes("\0")) {
throw new ArchiveError(`Invalid CPIO archive: symlink '${recordPath}' has an invalid UTF-8 target`);
}
const portableTarget = rawTarget.replace(/\\/g, "/");
if (path.posix.isAbsolute(portableTarget)) return { path: portableTarget, resolveTarget: false };
const normalized = normalizeArchiveLookupPath(path.posix.join(path.posix.dirname(recordPath), portableTarget));
return normalized === undefined
? { path: portableTarget, resolveTarget: false }
: { path: normalized, resolveTarget: true };
}
/** Parse an already-materialized CPIO stream for direct and RPM-composed readers. */
export function readCpioEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[] {
assertInMemorySize(bytes.byteLength, options.limits);
const records: ParsedRecord[] = [];
let offset = 0;
let metadataSize = 0;
let foundTrailer = false;
while (offset < bytes.byteLength) {View on GitHub (pinned to 9690622007)
Solutions
- Recreate the archive so symlink targets are UTF-8 encoded (set a UTF-8 locale or convert filenames)
- If the archive is legitimately non-UTF-8, transcode it before parsing (repack with bsdtar or GNU cpio after fixing encoding)
- Inspect the named symlink's data bytes to confirm whether it is corruption or encoding mismatch
- Exclude or pre-process entries with binary targets if your pipeline controls archive creation
Example fix
// before: writing raw platform bytes as target
writer.addSymlink('link', Buffer.from(targetName, 'latin1'));
// after: enforce UTF-8
writer.addSymlink('link', Buffer.from(targetName, 'utf8')); Defensive patterns
Strategy: try-catch
Validate before calling
// when creating archives, guarantee UTF-8 symlink targets:
if (!Buffer.from(target, 'utf8').equals(Buffer.from(target))) throw new Error('symlink target must be UTF-8'); Try / catch
try {
const entries = await readCpio(source, options);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('invalid UTF-8 target')) {
// transcode the archive (repack with UTF-8 filenames) or skip affected symlinks
} else throw err;
} Prevention
- Create archives under a UTF-8 locale so filenames/targets are UTF-8
- Reject or transcode non-UTF-8 archives at ingestion (repack with bsdtar)
- Never include NUL inside symlink target content; count the terminator only in fileSize as your writer intends
- Pre-scan entries with symlink mode for invalid UTF-8 if you control the writer
When it happens
Trigger: readCpio/readRpmArchive/entries parsing a CPIO containing a symlink (mode 0o120xxx) whose data payload (the target path) is non-UTF-8 (e.g. Latin-1 encoded filename) or NUL-contaminated, e.g. the writer included the terminating NUL inside the target content while fileSize also counted it twice.
Common situations: Archives created on systems with non-UTF-8 locales/filesystems; old tooling writing raw filesystem bytes for targets; corrupt or truncated entries where a NUL sneaks into target bytes.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid CAB archive: file name is not valid UTF-8
- Invalid RPM package: tag ${tag} is not valid UTF-8
- invalid utf-8 sequence
- invalid byte sequence: {:02x?}
- Failed to encode ASAR archive: ${describeError(error)}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/839b9b9687b050c5.
Report an issue: GitHub.