{"record":{"id":"f1203236fa437925","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-non-canonical-variable-length-i","errorCode":null,"errorMessage":"Invalid XZ stream: non-canonical variable-length integer","messagePattern":"Invalid XZ stream: non-canonical variable-length integer","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":47,"sourceCode":"\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;\n\tcheckId: number;\n\trecords: XzRecord[];","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L29-L65","documentation":"XZ varints must be canonically encoded: continuation padding bytes after the final (non-continuation) byte must be zero. A zero data byte in a non-final position means either non-canonical encoding (rejected by the spec) or corrupt data.","triggerScenarios":"readVarInt reads a byte === 0 at index > 0 — i.e. a 0x00 where a meaningful payload or 0x80-continuation byte was required.","commonSituations":"Corrupted .xz stream, hand-crafted or fuzzed varints, zero-fill overwriting part of an index/block header.","solutions":["Re-download or re-compress the .xz file with a standard tool (xz, liblzma).","Locate corruption with `xz -t file.xz` outside the library.","Treat as invalid input; the library intentionally rejects non-canonical encodings per the XZ format spec."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// reject obviously corrupt varint prefixes before parsing\nfunction varintRegionLooksSane(bytes, offset, limit) {\n  return offset >= 0 && offset <= limit && limit <= bytes.byteLength;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const idx = parseIndex(bytes, indexOffset);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"non-canonical\")) {\n    throw new Error(\"XZ stream contains non-canonical/corrupt size fields\");\n  }\n  throw err;\n}","preventionTips":["Verify archive integrity with `xz -t` or CRC before parsing","Only parse .xz files produced by standard compressors","Treat non-canonical encodings as corruption, not a recoverable condition"],"tags":["archive","xz","varint","corrupt-data"],"backgroundTag":"corrupt-archive-data","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}