{"record":{"id":"821756618aeb8d5d","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-truncated-variable-length-integ","errorCode":null,"errorMessage":"Invalid XZ stream: truncated variable-length integer","messagePattern":"Invalid XZ stream: truncated variable-length integer","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":45,"sourceCode":"\tbytes[offset + 3] = value & 0xff;\n}\n\nfunction equalBytes(left: Uint8Array, right: Uint8Array): boolean {\n\tif (left.byteLength !== right.byteLength) return false;\n\tfor (let index = 0; index < left.byteLength; index++) if (left[index] !== right[index]) return false;\n\treturn true;\n}\n\ninterface Cursor {\n\tbytes: Uint8Array;\n\tpos: number;\n\tlimit: number;\n}\n\nfunction readVarInt(cursor: Cursor): number {\n\tlet value = 0;\n\tfor (let index = 0; index < 9; index++) {\n\t\tif (cursor.pos >= cursor.limit) throw new ArchiveError(\"Invalid XZ stream: truncated variable-length integer\");\n\t\tconst byte = cursor.bytes[cursor.pos++]!;\n\t\tif (index > 0 && byte === 0) throw new ArchiveError(\"Invalid XZ stream: non-canonical variable-length integer\");\n\t\tvalue += (byte & 0x7f) * 2 ** (index * 7);\n\t\tif (!Number.isSafeInteger(value)) throw new ArchiveError(\"XZ stream uses sizes too large to read safely\");\n\t\tif ((byte & 0x80) === 0) return value;\n\t}\n\tthrow new ArchiveError(\"Invalid XZ stream: variable-length integer is too long\");\n}\n\ninterface XzRecord {\n\tunpaddedSize: number;\n\tuncompressedSize: number;\n}\n\ninterface XzStream {\n\tstart: number;\n\tindexStart: number;\n\tfooterStart: number;","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L27-L63","documentation":"XZ variable-length integers (multibyte, up to 9 bytes) encode sizes in the block header and index. readVarInt throws when the cursor reaches its limit before encountering a byte with the continuation bit clear — the integer is cut off by the end of the valid region.","triggerScenarios":"Parsing index records (count, unpaddedSize, uncompressedSize) or block header fields (declaredCompressed, declaredUncompressed, filter id) where the cursor limit is hit mid-integer.","commonSituations":"Truncated .xz file cut off mid-index or mid-block-header; wrong limit passed to the index parser so the region ends inside a varint.","solutions":["Re-download the archive; a truncated tail cannot be recovered for indexed streams.","Check that the index region passed to parseIndex matches the stream's actual backward size.","Validate the file against checksums before parsing."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify the index region fits: last 12 bytes are footer, index backward size is in it\nif (bytes.byteLength < 12) throw new Error(\"XZ stream too short to contain an index\");","typeGuard":null,"tryCatchPattern":"try {\n  const idx = parseIndex(bytes, indexOffset);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"truncated variable-length\")) {\n    throw new Error(\"XZ index is truncated — file incomplete\");\n  }\n  throw err;\n}","preventionTips":["Validate the stream footer and backward size before parsing the index","Re-download truncated files instead of parsing partial data","Confirm the index offset/limit covers the full index region"],"tags":["archive","xz","varint","truncation"],"backgroundTag":"truncated-archive-stream","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}