{"record":{"id":"360eb282cbd28a48","repo":"can1357/oh-my-pi","slug":"unpacked-asar-file-label-is-a-directory","errorCode":null,"errorMessage":"Unpacked ASAR file '${label}' is a directory","messagePattern":"Unpacked ASAR file '(.+?)' is a directory","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/asar.ts","lineNumber":160,"sourceCode":"\t\tthis.#filePath = filePath;\n\t\tthis.#size = size;\n\t\tthis.#integrity = integrity;\n\t}\n\n\tasync read(size: number, memberPath: string): Promise<Uint8Array> {\n\t\tconst label = formatArchivePathForError(memberPath);\n\t\tif (size !== this.#size) {\n\t\t\tthrow new ArchiveError(`ASAR member '${label}' has an inconsistent size`);\n\t\t}\n\t\tif (!this.#filePath) {\n\t\t\tthrow new ArchiveError(`Archive file '${label}' is unpacked and requires a filesystem-backed ASAR archive`);\n\t\t}\n\t\tconst file = Bun.file(this.#filePath);\n\t\tconst stat = await file.stat().catch(() => {\n\t\t\tthrow new ArchiveError(`Unpacked ASAR file '${label}' was not found`);\n\t\t});\n\t\tif (stat.isDirectory()) {\n\t\t\tthrow new ArchiveError(`Unpacked ASAR file '${label}' is a directory`);\n\t\t}\n\t\tif (stat.size !== this.#size) {\n\t\t\tthrow new ArchiveError(\n\t\t\t\t`Unpacked ASAR file '${label}' size differs from its archive header (${stat.size} != ${this.#size} bytes)`,\n\t\t\t);\n\t\t}\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = await file.bytes();\n\t\t} catch (error) {\n\t\t\tthrow new ArchiveError(`Failed to read unpacked ASAR file '${label}': ${describeError(error)}`);\n\t\t}\n\t\tif (bytes.byteLength !== this.#size) {\n\t\t\tthrow new ArchiveError(`Unpacked ASAR file '${label}' changed while being read`);\n\t\t}\n\t\tverifyIntegrity(bytes, this.#integrity, memberPath);\n\t\treturn bytes;\n\t}","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/asar.ts#L142-L178","documentation":"Thrown when the stat of the unpacked sidecar path resolves to a directory rather than a regular file. The ASAR header declared a file member, but on disk the same path is a directory (e.g. a directory was unpacked as if it were a file, or path resolution landed on a folder).","triggerScenarios":"`<archive>.unpacked/<memberPath>` exists as a directory; a member name collides with a directory in the sidecar layout; broken repack tooling produced a directory at a file path.","commonSituations":"Hand-built .unpacked directories with wrong structure; symlinks pointing at directories; merging app bundles where a file was replaced by a folder (e.g. path 'foo' vs 'foo/bar').","solutions":["Inspect `<asar>.unpacked/<memberPath>` and fix it to be a regular file with the expected contents","Rebuild the .unpacked directory from a clean unpack of the original ASAR","Check the ASAR header entry — if the path should be a directory, the packer that produced the header is wrong"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const st = await fs.stat(sidecar);\nif (!st.isFile()) throw new Error(`${sidecar} is not a regular file`);","typeGuard":"const isRegularFile = (st) => st.isFile();","tryCatchPattern":"try { return await readMember(entry); } catch (e) { if (e instanceof ArchiveError && e.message.includes(\"is a directory\")) { /* fix or re-extract the .unpacked tree */ } throw e; }","preventionTips":["Rebuild .unpacked from a clean unpack rather than hand-crafting it","Validate sidecar layout after copying bundles","Watch for path collisions between files and directories with the same name"],"tags":["asar","unpacked-files","filesystem","path-resolution"],"backgroundTag":"asar-unpacked-file-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}