{"record":{"id":"44aaae5a0e6788f8","repo":"can1357/oh-my-pi","slug":"archive-hard-link-formatarchivepathforerror-ent-44aaae","errorCode":null,"errorMessage":"Archive hard link '${formatArchivePathForError(entry.path)}' targets directory '${formatArchivePathForError(pending.targetPath)}'","messagePattern":"Archive hard link '(.+?)' targets directory '(.+?)'","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/tar.ts","lineNumber":405,"sourceCode":"\t\tconst target = entries.get(targetPath);\n\t\tif (target?.storage && !target.isDirectory && !unresolved.has(target)) {\n\t\t\tentry.size = target.size;\n\t\t\tentry.storage = target.storage;\n\t\t\tcontinue;\n\t\t}\n\t\tconst targetIsDirectory = targetPath === \"\" || target?.isDirectory === true || directoryPrefixes.has(targetPath);\n\t\tif (!targetIsDirectory) {\n\t\t\tif (pending.kind === \"symlink\") {\n\t\t\t\tentry.storage = { type: \"link\", targetPath: pending.targetPath, resolveTarget: false };\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst reason = target ? \"unreadable member\" : \"missing member\";\n\t\t\tthrow new ArchiveError(\n\t\t\t\t`Archive hard link '${formatArchivePathForError(entry.path)}' targets ${reason} '${formatArchivePathForError(pending.targetPath)}'`,\n\t\t\t);\n\t\t}\n\t\tif (pending.kind === \"hard link\") {\n\t\t\tthrow new ArchiveError(\n\t\t\t\t`Archive hard link '${formatArchivePathForError(entry.path)}' targets directory '${formatArchivePathForError(pending.targetPath)}'`,\n\t\t\t);\n\t\t}\n\t\tentry.isDirectory = true;\n\t\tentry.storage = { type: \"link\", targetPath: pending.targetPath, resolveTarget: false };\n\t}\n\tif (unresolved.size > 0) throw new ArchiveError(\"Archive contains cyclic or unsupported links\");\n}\n\n/** Index an already-decompressed tar buffer with bounded GNU, ustar, and PAX handling. */\nexport function readTarEntriesFromBuffer(buffer: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[] {\n\tconst { limits } = options;\n\tassertInMemorySize(buffer.byteLength, limits);\n\tconst entries = new Map<string, ArchiveIndexEntry>();\n\tconst pendingLinks = new Map<ArchiveIndexEntry, PendingTarLink>();\n\tconst addEntry = (entry: ArchiveIndexEntry, pendingLink?: PendingTarLink): void => {\n\t\tconst existing = entries.get(entry.path);\n\t\tconst indexed = upsertArchiveEntry(entries, entry);","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/tar.ts#L387-L423","documentation":"Thrown when a tar hard link's target resolves to a directory. POSIX hard links cannot reference directories, so the library refuses to index such an entry rather than fabricating a directory.","triggerScenarios":"readTar on an archive with a typeflag-'1' entry whose linkname points at a directory entry (typeflag '5') or a path that is a directory prefix of other members.","commonSituations":"Corrupt or hand-crafted archives; archives migrated between systems where directory hard links were (incorrectly) serialized; old backup tools that recorded directory hard links.","solutions":["Find the offending hard link via `tar tvf` and remove it or convert it to a symlink.","Re-create the archive excluding directory hard links (`tar --exclude'...'` or fix the source tree).","Catch ArchiveError and reject the archive if it comes from an untrusted source."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await readTar(bytes, opts);\n} catch (e) {\n  if (e instanceof ArchiveError && e.message.includes(\"targets directory\")) {\n    throw new Error(\"Archive contains an illegal directory hard link\");\n  }\n  throw e;\n}","preventionTips":["Never hard-link directories when building archives (most tars forbid it already).","Convert directory hard links to symlinks if a reference is genuinely needed.","Reject such archives in security-sensitive pipelines."],"tags":["archive","tar","hardlink","directory"],"backgroundTag":"hardlink-target-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}