{"record":{"id":"36cfd7b02b74e57a","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-folder-data-is-shorter-than-i","errorCode":null,"errorMessage":"Invalid CAB archive: folder data is shorter than its file table declares","messagePattern":"Invalid CAB archive: folder data is shorter than its file table declares","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":170,"sourceCode":"\t\t\t\tthrow new ArchiveError(`Invalid CAB archive: CFDATA expands to ${uncompressed} bytes (maximum 32768)`);\n\t\t\t}\n\t\t\tconst payloadStart = position + DATA_BLOCK_SIZE + this.#dataReserveSize;\n\t\t\tconst payloadEnd = payloadStart + compressed;\n\t\t\tif (payloadEnd > bytes.byteLength) throw new ArchiveError(\"Invalid CAB archive: truncated CFDATA payload\");\n\t\t\tconst expectedChecksum = readUInt32LE(bytes, position);\n\t\t\tif (expectedChecksum !== 0) {\n\t\t\t\tconst payloadChecksum = cabChecksum(bytes.subarray(payloadStart, payloadEnd));\n\t\t\t\tconst actualChecksum = cabChecksum(bytes.subarray(position + 4, payloadStart), payloadChecksum);\n\t\t\t\tif (actualChecksum !== expectedChecksum) {\n\t\t\t\t\tthrow new ArchiveError(`Invalid CAB archive: CFDATA block ${block} checksum mismatch`);\n\t\t\t\t}\n\t\t\t}\n\t\t\toutputSize += uncompressed;\n\t\t\tassertInMemorySize(outputSize, this.#limits);\n\t\t\tposition = payloadEnd;\n\t\t}\n\t\tif (outputSize < description.requiredSize) {\n\t\t\tthrow new ArchiveError(\"Invalid CAB archive: folder data is shorter than its file table declares\");\n\t\t}\n\n\t\tconst output = new Uint8Array(outputSize);\n\t\tconst lzx = description.method === 3 ? new LzxDecoder(description.parameter) : undefined;\n\t\tposition = 0;\n\t\tlet outputPosition = 0;\n\t\tfor (let block = 0; block < description.blockCount; block++) {\n\t\t\tconst compressed = readUInt16LE(bytes, position + 4);\n\t\t\tconst uncompressed = readUInt16LE(bytes, position + 6);\n\t\t\tconst payloadStart = position + DATA_BLOCK_SIZE + this.#dataReserveSize;\n\t\t\tconst payloadEnd = payloadStart + compressed;\n\t\t\tconst payload = bytes.subarray(payloadStart, payloadEnd);\n\t\t\tlet decoded: Uint8Array;\n\t\t\tif (description.method === 0) {\n\t\t\t\tif (compressed !== uncompressed) {\n\t\t\t\t\tthrow new ArchiveError(\"Invalid CAB archive: uncompressed CFDATA sizes do not match\");\n\t\t\t\t}\n\t\t\t\tdecoded = payload;","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L152-L188","documentation":"Thrown by CabFolder.#decode after summing every block's declared uncompressed size: if the total is less than the maximum (offset+size) any CFFILE entry in this folder requires, the folder cannot supply the bytes its file table promises. The library cross-checks the folder data against the file table instead of returning short reads.","triggerScenarios":"readCab() built entries where some CFFILE's folderOffset+usize exceeded the sum of all CFDATA cbUncomp values for the folder; a malformed or tampered cabinet where the file table and data blocks disagree.","commonSituations":"Corrupted or deliberately malformed cabinets; cabinets produced by buggy third-party writers that mis-declare uncompressed sizes; fuzz-tested inputs.","solutions":["Verify the archive with `cabextract -t` or 7-Zip; if they also fail, the file is malformed","Regenerate the cabinet with a standard tool (makecab, 7-Zip, libmspack) if you control its production","Check whether the cabinet passed through a process that could rewrite bytes (text-mode transfer, encoding conversion)","Report a bug to the library only if cabextract succeeds but this reader fails"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-validate: an independent tool round-trip\nconst t = Bun.$`cabextract -t ${path}`.quiet().nothrow();\nif ((await t).exitCode !== 0) throw new Error(`malformed cabinet: ${path}`);","typeGuard":null,"tryCatchPattern":"try {\n  await readCab(source, opts);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('folder data is shorter'))\n    throw new Error('Cabinet file table is inconsistent with its data — file is malformed.');\n  throw err;\n}","preventionTips":["Only process cabinets from trusted producers or validated pipelines","Reject untrusted archives up front with a tool-based integrity check","Include the failing file in error reports to distinguish writer bugs from reader bugs"],"tags":["archive","cab","corruption","malformed"],"backgroundTag":"archive-structure-invalid","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}