{"record":{"id":"839b9b9687b050c5","repo":"can1357/oh-my-pi","slug":"invalid-cpio-archive-symlink-recordpath-has","errorCode":null,"errorMessage":"Invalid CPIO archive: symlink '${recordPath}' has an invalid UTF-8 target","messagePattern":"Invalid CPIO archive: symlink '(.+?)' has an invalid UTF-8 target","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cpio.ts","lineNumber":206,"sourceCode":"function decodeUtf8(bytes: Uint8Array): string | undefined {\n\ttry {\n\t\treturn UTF8_FATAL_DECODER.decode(bytes);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction validateZeroPadding(bytes: Uint8Array, start: number, end: number, what: string): void {\n\tfor (let offset = start; offset < end; offset++) {\n\t\tif (bytes[offset] !== 0) throw new ArchiveError(`Invalid CPIO archive: non-zero ${what} padding`);\n\t}\n}\n\nfunction makeLinkTarget(recordPath: string, targetBytes: Uint8Array, maxPathBytes: number): LinkTarget {\n\tassertArchivePathBytes(targetBytes.byteLength, \"link target\", maxPathBytes);\n\tconst rawTarget = decodeUtf8(targetBytes);\n\tif (rawTarget === undefined || rawTarget.includes(\"\\0\")) {\n\t\tthrow new ArchiveError(`Invalid CPIO archive: symlink '${recordPath}' has an invalid UTF-8 target`);\n\t}\n\tconst portableTarget = rawTarget.replace(/\\\\/g, \"/\");\n\tif (path.posix.isAbsolute(portableTarget)) return { path: portableTarget, resolveTarget: false };\n\tconst normalized = normalizeArchiveLookupPath(path.posix.join(path.posix.dirname(recordPath), portableTarget));\n\treturn normalized === undefined\n\t\t? { path: portableTarget, resolveTarget: false }\n\t\t: { path: normalized, resolveTarget: true };\n}\n\n/** Parse an already-materialized CPIO stream for direct and RPM-composed readers. */\nexport function readCpioEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[] {\n\tassertInMemorySize(bytes.byteLength, options.limits);\n\tconst records: ParsedRecord[] = [];\n\tlet offset = 0;\n\tlet metadataSize = 0;\n\tlet foundTrailer = false;\n\n\twhile (offset < bytes.byteLength) {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cpio.ts#L188-L224","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: writing raw platform bytes as target\nwriter.addSymlink('link', Buffer.from(targetName, 'latin1'));\n// after: enforce UTF-8\nwriter.addSymlink('link', Buffer.from(targetName, 'utf8'));","handlingStrategy":"try-catch","validationCode":"// when creating archives, guarantee UTF-8 symlink targets:\nif (!Buffer.from(target, 'utf8').equals(Buffer.from(target))) throw new Error('symlink target must be UTF-8');","typeGuard":null,"tryCatchPattern":"try {\n  const entries = await readCpio(source, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('invalid UTF-8 target')) {\n    // transcode the archive (repack with UTF-8 filenames) or skip affected symlinks\n  } else throw err;\n}","preventionTips":["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"],"tags":["archive","cpio","symlink","utf-8","encoding"],"backgroundTag":"invalid-utf8-path","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}