{"record":{"id":"4104f8662fec2299","repo":"can1357/oh-my-pi","slug":"invalid-lzh-filename-length","errorCode":null,"errorMessage":"Invalid LZH filename length","messagePattern":"Invalid LZH filename length","errorType":"validation","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":486,"sourceCode":"\tlet size = u32(bytes, offset + 11);\n\tlet crc = 0;\n\tlet legacyFilename: string | undefined;\n\tlet mtimeMs: number | undefined;\n\tlet osId = 0;\n\tlet dataStart: number;\n\tconst fields: LzhExtendedFields = {};\n\n\tif (level < 2) {\n\t\tconst headerLength = bytes[offset]!;\n\t\tconst minimum = level === 0 ? 22 : 25;\n\t\tif (headerLength < minimum) throw new ArchiveError(`Invalid LZH level-${level} header size`);\n\t\tconst baseEnd = offset + headerLength + 2;\n\t\tassertRange(bytes, offset, baseEnd, \"header\");\n\t\tlet sum = 0;\n\t\tfor (let index = offset + 2; index < baseEnd; index++) sum = (sum + bytes[index]!) & 0xff;\n\t\tif (sum !== bytes[offset + 1]) throw new ArchiveError(\"Invalid LZH header checksum\");\n\t\tconst nameLength = bytes[offset + 21]!;\n\t\tif (22 + nameLength + 2 > headerLength + 2) throw new ArchiveError(\"Invalid LZH filename length\");\n\t\tassertArchivePathBytes(nameLength, \"member path\", options.limits.maxPathBytes);\n\t\tlegacyFilename = decodeLegacy(bytes.subarray(offset + 22, offset + 22 + nameLength));\n\t\tcrc = u16(bytes, offset + 22 + nameLength);\n\t\tmtimeMs = dosTimeToMs(u32(bytes, offset + 15));\n\t\tif (level === 0) {\n\t\t\tconst extendedStart = offset + 24 + nameLength;\n\t\t\tif (baseEnd - extendedStart >= 12) {\n\t\t\t\tconst extended = bytes.subarray(extendedStart, baseEnd);\n\t\t\t\tif ((extended[0] === 0x55 || extended[0] === 0x4b) && extended[1] === 0) {\n\t\t\t\t\tosId = extended[0]!;\n\t\t\t\t\tfields.mtimeMs = u32(extended, 2) * 1000;\n\t\t\t\t\tfields.mode = u16(extended, extended.byteLength - 6);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdataStart = baseEnd;\n\t\t} else {\n\t\t\tosId = bytes[offset + 24 + nameLength]!;\n\t\t\tlet extensionSize = u16(bytes, baseEnd - 2);","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L468-L504","documentation":"Thrown when a level-0/1 LZH header's filename-length byte claims a name that would extend past the declared header length (22 + nameLength + 2 > headerLength + 2). The header is internally inconsistent — it does not have room for the advertised filename plus CRC.","triggerScenarios":"Reading an archive with a corrupt or hostile filename-length byte, or a header written by a tool that miscounts its own header size.","commonSituations":"Malformed archives from unreliable packers, fuzzed inputs, or truncated files where downstream bytes are zeros/garbage.","solutions":["Replace the archive with an intact copy","Repack with a standard tool (lha, 7-zip)","If the input is untrusted, treat this as a rejection signal — do not attempt recovery"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"const nameLength = bytes[21]; if (nameLength > 255 || 24 + nameLength > bytes[0] + 2) throw new Error('bad name length');","typeGuard":null,"tryCatchPattern":"try { parse(); } catch (err) { if (err instanceof ArchiveError) reject(err.message); else throw err; }","preventionTips":["Bound-check header fields yourself for untrusted input","Reject on first inconsistency"],"tags":["archive","lzh","header","validation","malformed"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}