{"record":{"id":"83262ae60ae76aa8","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-truncated-cfheader","errorCode":null,"errorMessage":"Invalid CAB archive: truncated CFHEADER","messagePattern":"Invalid CAB archive: truncated CFHEADER","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":244,"sourceCode":"\t\tthis.#offset = offset;\n\t\tthis.#declaredSize = size;\n\t}\n\n\tasync read(size: number, memberPath: string): Promise<Uint8Array> {\n\t\tif (size !== this.#declaredSize) {\n\t\t\tthrow new ArchiveError(`Invalid CAB archive: size changed while extracting '${memberPath}'`);\n\t\t}\n\t\tconst folder = await this.#folder.readAll();\n\t\tconst end = this.#offset + size;\n\t\tif (!Number.isSafeInteger(end) || this.#offset < 0 || end > folder.byteLength) {\n\t\t\tthrow new ArchiveError(`Invalid CAB archive: member '${memberPath}' is outside its folder data`);\n\t\t}\n\t\treturn folder.slice(this.#offset, end);\n\t}\n}\n\nasync function readCabArchive(source: ByteSource, options: Parameters<FormatReader>[1]): Promise<ArchiveIndexEntry[]> {\n\tif (source.size < FIXED_HEADER_SIZE) throw new ArchiveError(\"Invalid CAB archive: truncated CFHEADER\");\n\tconst fixed = await readExact(source, 0, FIXED_HEADER_SIZE);\n\tif (!hasSignature(fixed)) throw new ArchiveError(`Invalid CAB archive: expected ${CAB_SIGNATURE} signature`);\n\tif (readUInt32LE(fixed, 4) !== 0 || readUInt32LE(fixed, 12) !== 0 || readUInt32LE(fixed, 20) !== 0) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: reserved CFHEADER fields must be zero\");\n\t}\n\tconst cabinetSize = readUInt32LE(fixed, 8);\n\tif (cabinetSize < FIXED_HEADER_SIZE || cabinetSize > source.size) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: declared cabinet size is out of bounds\");\n\t}\n\tconst fileTableOffset = readUInt32LE(fixed, 16);\n\tif (fileTableOffset < FIXED_HEADER_SIZE || fileTableOffset > cabinetSize) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: CFFILE table offset is out of bounds\");\n\t}\n\tif (fixed[24] !== 3 || fixed[25] !== 1) {\n\t\tthrow new ArchiveError(`Unsupported CAB format version ${fixed[25]}.${fixed[24]} (expected 1.3)`);\n\t}\n\tconst folderCount = readUInt16LE(fixed, 26);\n\tconst fileCount = readUInt16LE(fixed, 28);","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L226-L262","documentation":"Thrown by readCabArchive when the ByteSource is smaller than the 36-byte fixed CFHEADER, so no CAB header could possibly be present. This is the first structural check in CAB indexing — it fires on empty files, tiny files, or streams that ended before the header arrived.","triggerScenarios":"Calling readCab on a source with size < 36: empty file, a few-byte stub, a truncated download, or passing the wrong file/path to the reader.","commonSituations":"Zero-byte files created by failed downloads; accidentally pointing the extractor at a lock/partial file; reading from a truncated network response.","solutions":["Check the file size on disk (ls -l / stat) — if it is tiny or 0, re-download or re-copy the archive","Confirm you are pointing the reader at the .cab file, not an index/manifest or temp file","Verify the upstream transfer completed (Content-Length match, checksum comparison)","If reading from a stream, ensure the source reports the true size and was fully consumed/flushed before indexing"],"exampleFix":"// before\nconst archive = Bun.file(maybePath);\nawait readCab(new ByteSource(archive), opts);\n// after\nconst archive = Bun.file(maybePath);\nif (archive.size < 36) throw new Error(`${maybePath} is too small to be a CAB archive (${archive.size} bytes)`);\nawait readCab(new ByteSource(archive), opts);","handlingStrategy":"validation","validationCode":"const file = Bun.file(path);\nconst stat = await file.stat();\nif (stat.size < 36) throw new Error(`${path} is ${stat.size} bytes — too small to be a CAB archive`);","typeGuard":null,"tryCatchPattern":"try {\n  await readCab(source, opts);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('truncated CFHEADER'))\n    throw new Error(`File is not a complete CAB archive (${source.size} bytes): ${path}`);\n  throw err;\n}","preventionTips":["Check file size before pointing the reader at a path","Confirm downloads completed (Content-Length / hash) before extraction","Exclude zero-byte or placeholder files from archive processing pipelines"],"tags":["archive","cab","truncated","header"],"backgroundTag":"archive-truncated","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}