{"record":{"id":"1d0090324de21207","repo":"can1357/oh-my-pi","slug":"invalid-lzh-archive-header","errorCode":null,"errorMessage":"Invalid LZH archive header","messagePattern":"Invalid LZH archive header","errorType":"validation","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":613,"sourceCode":"\tconst method = String.fromCharCode(...bytes.subarray(2, 7));\n\treturn LHA_METHOD_PATTERN.test(method) && bytes[20]! <= 2;\n}\n\n/** Index an LZH/LHA archive and lazily decode its members from the bounded archive buffer. */\nexport const readLzh: FormatReader = async (\n\tsource: ByteSource,\n\toptions: FormatReadOptions,\n): Promise<ArchiveIndexEntry[]> => {\n\tassertInMemorySize(source.size, options.limits);\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = await readAllBytes(source);\n\t} catch (error) {\n\t\tif (error instanceof ArchiveError) throw error;\n\t\tthrow new ArchiveError(`Unable to read LZH archive: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (bytes.byteLength !== source.size) throw new ArchiveError(\"Invalid LZH archive: truncated data\");\n\tif (!sniffLzh(bytes)) throw new ArchiveError(\"Invalid LZH archive header\");\n\tconst entries: ArchiveIndexEntry[] = [];\n\tlet offset = 0;\n\tlet parsedCount = 0;\n\tlet metadataSize = 0;\n\twhile (offset < bytes.byteLength && bytes[offset] !== 0) {\n\t\tconst header = parseLzhHeader(bytes, offset, options);\n\t\tmetadataSize += header.dataStart - offset;\n\t\tassertIndexSize(metadataSize, options.limits, \"index\");\n\t\tassertEntryCount(++parsedCount, options.limits);\n\t\tif (header.nextOffset <= offset) throw new ArchiveError(\"Invalid LZH archive: header did not advance\");\n\t\toffset = header.nextOffset;\n\t\tif (!header.path) continue;\n\t\tconst isDirectory = header.method === \"-lhd-\";\n\t\tif (isDirectory && header.mode !== undefined && (header.mode & 0xf000) === 0xa000) {\n\t\t\tconst separator = header.path.indexOf(\"|\");\n\t\t\tif (separator < 1) throw new ArchiveError(`Invalid LZH symbolic link '${header.path}'`);\n\t\t\tconst path = normalizeArchiveEntryPath(header.path.slice(0, separator));\n\t\t\tconst targetPath = normalizeArchiveEntryPath(header.path.slice(separator + 1));","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L595-L631","documentation":"sniffLzh() checks the opening bytes look like an LZH member header: at least 22 bytes, the method string starting with '-l' at offset 2 and ending '-' at offset 6, a valid compression-method pattern, and header level <= 2. Files that fail are not LZH at all, so the reader refuses them before any parsing.","triggerScenarios":"readLzh() called on bytes that are not an LZH/LHA archive: a different archive format (zip, gzip, 7z), a plain text/binary file, or an empty file renamed to .lzh.","commonSituations":"Wrong format passed by mistake; server returned an HTML error page saved as .lzh; MacBinary/BinHex wrapper around an LHA file; file extension renamed without conversion.","solutions":["Confirm the file's actual type (file(1) command or magic bytes) and use the correct format reader.","If it is a self-extracting or wrapped LHA (BinHex, MacBinary), strip the wrapper first.","Re-download if the 'archive' is actually an HTML/text error page.","Call sniffLzh() yourself (exported) to gate before invoking readLzh."],"exampleFix":"// before\nconst entries = await readLzh(source, options);\n// after\nconst bytes = await readAllBytes(source);\nif (!sniffLzh(bytes)) throw new Error(\"not an LZH archive — check the file type\");\nconst entries = await readLzh(source, options);","handlingStrategy":"type-guard","validationCode":"const bytes = await readAllBytes(source);\nif (!sniffLzh(bytes)) throw new Error(\"not an LZH archive — check the file type with `file`\");","typeGuard":"function looksLikeLzh(buf: Uint8Array): boolean {\n  return sniffLzh(buf);\n}","tryCatchPattern":"try {\n  const entries = await readLzh(source, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message === \"Invalid LZH archive header\") {\n    throw new Error(\"input is not LZH — detect the real format (zip/gzip/7z?) and use the right reader\");\n  }\n  throw err;\n}","preventionTips":["Detect archive format by magic bytes, never by file extension","Gate format dispatch with the exported sniffLzh() helper","Handle SFX/wrapped LHA (MacBinary, BinHex) by stripping wrappers first"],"tags":["archive","lzh","wrong-file-type","format-detection"],"backgroundTag":"invalid-magic-bytes","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}