{"record":{"id":"d517b474a7aa87e2","repo":"can1357/oh-my-pi","slug":"truncated-compress-z-code-group","errorCode":null,"errorMessage":"Truncated compress (.Z) code group","messagePattern":"Truncated compress \\(\\.Z\\) code group","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/lzw.ts","lineNumber":38,"sourceCode":"\n\tread(width: number): number | undefined {\n\t\tif (this.remainingBits < width) {\n\t\t\treturn undefined;\n\t\t}\n\t\tlet value = 0;\n\t\tfor (let bit = 0; bit < width; bit++) {\n\t\t\tconst position = this.#bitPosition + bit;\n\t\t\tvalue += ((this.#bytes[position >>> 3]! >>> (position & 7)) & 1) * 2 ** bit;\n\t\t}\n\t\tthis.#bitPosition += width;\n\t\treturn value;\n\t}\n\n\talignCodeGroup(width: number): void {\n\t\tconst groupBits = width * 8;\n\t\tconst aligned = this.#groupStart + Math.ceil((this.#bitPosition - this.#groupStart) / groupBits) * groupBits;\n\t\tif (aligned > this.#bytes.byteLength * 8) {\n\t\t\tthrow new ArchiveError(\"Truncated compress (.Z) code group\");\n\t\t}\n\t\tthis.#bitPosition = aligned;\n\t\tthis.#groupStart = aligned;\n\t}\n\n\tassertFinalPadding(): void {\n\t\tthis.#assertZeroBits(this.#bytes.byteLength * 8);\n\t}\n\n\t#assertZeroBits(end: number): void {\n\t\tfor (let position = this.#bitPosition; position < end; position++) {\n\t\t\tif (((this.#bytes[position >>> 3]! >>> (position & 7)) & 1) !== 0) {\n\t\t\t\tthrow new ArchiveError(\"Invalid non-zero compress (.Z) padding\");\n\t\t\t}\n\t\t}\n\t}\n}\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/lzw.ts#L20-L56","documentation":"compress (.Z) codes are read in groups whose width starts at 9 bits and grows as the code table expands; alignCodeGroup snaps the bit position to the next width-byte boundary. This error is thrown when the computed group boundary lies beyond the end of the input, meaning the stream was cut off before the current code group completed.","triggerScenarios":"Calling alignCodeGroup (during decode/lzwDecompress) when the remaining input bits are fewer than needed to reach the next width-aligned boundary — i.e. the input ends mid-group.","commonSituations":"Truncated .Z file from an incomplete download or interrupted transfer; reading fewer bytes than the compressed stream requires; corrupted archive tail.","solutions":["Re-download/re-copy the .Z file and verify its size (e.g. with `compress -c | wc -c` comparison or `zcat` test).","Check the code that reads the file — ensure it reads the full file (use Bun.file().bytes() / complete readFile) rather than a partial buffer.","Test the file with `zcat file.Z > /dev/null` to confirm it decompresses outside this library.","If concatenating .Z members, split on member boundaries instead of appending raw compressed bytes."],"exampleFix":"// before: partial read\nconst bytes = buf.subarray(0, 512);\nlzwDecompress(bytes, max);\n// after: full file\nconst bytes = new Uint8Array(await Bun.file(path).arrayBuffer());\nlzwDecompress(bytes, max);","handlingStrategy":"validation","validationCode":"if (bytes.byteLength < 3 || bytes[0] !== 0x1f || bytes[1] !== 0x9d) throw new Error(\"Not a compress (.Z) stream\");","typeGuard":null,"tryCatchPattern":"try {\n  return lzwDecompress(bytes, maxOutput);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"code group\")) {\n    throw new Error(\".Z stream is truncated (ends mid code group) — re-obtain the file\", { cause: err });\n  }\n  throw err;\n}","preventionTips":["Verify the .Z magic (0x1F 0x9D) and full file size before decoding.","Cross-check with `zcat file.Z > /dev/null` when a file from an external source fails.","Read files completely — avoid fixed-size partial reads.","Treat as fatal corruption; retrying decode on the same bytes will not help."],"tags":["archive","lzw","compress-z","truncated-input"],"backgroundTag":"truncated-compressed-stream","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}