{"record":{"id":"870f46bc80514c6e","repo":"can1357/oh-my-pi","slug":"invalid-cpio-archive-truncated-what","errorCode":null,"errorMessage":"Invalid CPIO archive: truncated ${what}","messagePattern":"Invalid CPIO archive: truncated (.+?)","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cpio.ts","lineNumber":100,"sourceCode":"\tlet checksum = 0;\n\tfor (const byte of bytes) checksum = (checksum + byte) >>> 0;\n\treturn checksum;\n}\n\nfunction align(value: number, alignment: number): number {\n\tconst remainder = value % alignment;\n\treturn remainder === 0 ? value : value + alignment - remainder;\n}\n\nfunction requireRange(bytes: Uint8Array, start: number, end: number, what: string): void {\n\tif (\n\t\t!Number.isSafeInteger(start) ||\n\t\t!Number.isSafeInteger(end) ||\n\t\tstart < 0 ||\n\t\tend < start ||\n\t\tend > bytes.byteLength\n\t) {\n\t\tthrow new ArchiveError(`Invalid CPIO archive: truncated ${what}`);\n\t}\n}\n\nfunction parseDigits(bytes: Uint8Array, offset: number, length: number, radix: 8 | 16, field: string): number {\n\trequireRange(bytes, offset, offset + length, `${field} field`);\n\tlet value = 0;\n\tfor (let index = offset; index < offset + length; index++) {\n\t\tconst code = bytes[index]!;\n\t\tlet digit: number;\n\t\tif (code >= 0x30 && code <= 0x39) digit = code - 0x30;\n\t\telse if (radix === 16 && code >= 0x41 && code <= 0x46) digit = code - 0x41 + 10;\n\t\telse if (radix === 16 && code >= 0x61 && code <= 0x66) digit = code - 0x61 + 10;\n\t\telse throw new ArchiveError(`Invalid CPIO archive: ${field} is not a valid base-${radix} number`);\n\t\tif (digit >= radix) throw new ArchiveError(`Invalid CPIO archive: ${field} is not a valid base-${radix} number`);\n\t\tvalue = value * radix + digit;\n\t}\n\tif (!Number.isSafeInteger(value)) throw new ArchiveError(`Invalid CPIO archive: ${field} is too large`);\n\treturn value;","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cpio.ts#L82-L118","documentation":"requireRange validates that a requested byte range [start,end) lies within the CPIO buffer; when it does not, the archive is reported as 'truncated <what>' (which field, e.g. 'ino field' or 'magic field'). It is the bounds-check used while parsing header fields and entries, so any header that runs past EOF produces this error.","triggerScenarios":"Calling readCpioEntriesFromBuffer on truncated data; header fields extending past end-of-buffer due to a corrupted size/count field; parsing at a wrong offset inside a larger container so field reads run past the buffer end.","commonSituations":"Partial initramfs/cpio downloads; wrong offset when extracting a cpio embedded in a firmware image; format confusion (parsing an 'odc' file as 'newc' with wrong field widths); zero-length or empty cpio files.","solutions":["Re-acquire a complete archive and retry","Verify the cpio parses with the system tool: cpio -it < file","Check the offset/base you are parsing from if the cpio is embedded in a larger file","Confirm the format matches what the parser expects (odc vs newc)"],"exampleFix":"// before: wrong offset into container\nconst entries = await readCpioEntriesFromBuffer(container.subarray( guessedOffset ));\n// after: locate the real cpio start (magic '070701' for newc)\nconst magicIndex = container.indexOf(Buffer.from('070701', 'ascii'));\nconst entries = await readCpioEntriesFromBuffer(container.subarray(magicIndex));","handlingStrategy":"validation","validationCode":"function looksLikeCpio(bytes: Uint8Array): boolean {\n  const magic = Buffer.from(bytes.subarray(0, 6)).toString('ascii');\n  return magic === '070701' || magic === '070702' || magic === '070707';\n}\nif (!looksLikeCpio(bytes) || bytes.byteLength < 110) throw new Error('not a (complete) cpio archive');","typeGuard":"function looksLikeCpio(bytes: Uint8Array): boolean {\n  const magic = Buffer.from(bytes.subarray(0, 6)).toString('ascii');\n  return magic === '070701' || magic === '070702' || magic === '070707';\n}","tryCatchPattern":"try {\n  const entries = await readCpioEntriesFromBuffer(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && /^Invalid CPIO archive: truncated/.test(err.message)) {\n    // message names which field ran past EOF; usually a truncated file or wrong offset\n    throw new Error(`cpio unreadable (${err.message}); re-acquire or fix parse offset`);\n  } else throw err;\n}","preventionTips":["Check the magic bytes before parsing","When cpio is embedded, derive the start offset from the magic string, never a guess","Confirm archive completeness (size or digest) before parsing"],"tags":["cpio","archive","truncation","bounds"],"backgroundTag":"archive-truncated","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}