{"record":{"id":"f8f5532581c7be8c","repo":"ruvnet/ruflo","slug":"section-sec-id-extends-beyond-buffer-offset","errorCode":null,"errorMessage":"Section \"${sec.id}\" extends beyond buffer (offset=${sec.offset}, size=${sec.size}, bufLen=${totalSize})","messagePattern":"Section \"(.+?)\" extends beyond buffer \\(offset=(.+?), size=(.+?), bufLen=(.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/appliance/rvfa-format.ts","lineNumber":361,"sourceCode":"    try {\n      parsed = JSON.parse(headerSlice.toString('utf-8'));\n    } catch {\n      throw new Error('Failed to parse RVFA header JSON');\n    }\n\n    if (!validateHeader(parsed)) {\n      throw new Error('RVFA header failed validation');\n    }\n    const header = parsed as RvfaHeader;\n\n    // Bounds-check every section offset\n    const totalSize = buf.length;\n    for (const sec of header.sections) {\n      if (sec.offset < 0 || sec.size < 0) {\n        throw new Error(`Section \"${sec.id}\" has negative offset or size`);\n      }\n      if (sec.offset + sec.size > totalSize - SHA256_SIZE) {\n        throw new Error(\n          `Section \"${sec.id}\" extends beyond buffer ` +\n            `(offset=${sec.offset}, size=${sec.size}, bufLen=${totalSize})`,\n        );\n      }\n    }\n\n    // Check for overlapping sections\n    const sorted = [...header.sections].sort((a, b) => a.offset - b.offset);\n    for (let i = 1; i < sorted.length; i++) {\n      const prev = sorted[i - 1];\n      const curr = sorted[i];\n      if (prev.offset + prev.size > curr.offset) {\n        throw new Error(\n          `Sections \"${prev.id}\" and \"${curr.id}\" overlap ` +\n            `(${prev.offset}+${prev.size} > ${curr.offset})`,\n        );\n      }\n    }","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/appliance/rvfa-format.ts#L343-L379","documentation":"A section in the header declares offset + size extending past buf.length - 32 (the reader reserves the last 32 bytes for the SHA256 footer). Unlike the constructor-time 'Buffer too small' check, the preamble and header parsed fine — the section data region itself is short. Almost always a truncated file: the header was written first, the payload didn't fully land.","triggerScenarios":"RvfaReader.fromBuffer/fromFile where the largest section (typically 'kernel' or 'runtime') runs past the end — e.g. an image cut off mid-download, or a buffer assembled by concatenating preamble+header with only part of the section data before the footer.","commonSituations":"Partial downloads (interrupted curl/scp); CI artifacts capped by max-size limits; disk exhaustion during image write; tests that build a header describing N sections but concatenate only N-1 payloads.","solutions":["Compare file size with the source and re-transfer — compute expected size as last section's offset + size + 32 from the header","If self-assembling buffers, ensure every staged section's data is actually concatenated in build() before the 32-byte footer","Run the image through its integrity check (verify() / footer SHA256) to confirm truncation before re-downloading","Check free disk space at the write location — ENOSPC often surfaces later as this read error"],"exampleFix":"// before — sections described but payload omitted\nconst out = Buffer.concat([preamble, headerJson, sec0, footer]); // sec1 missing\n\n// after — concatenate every staged section, then footer\nconst out = Buffer.concat([preamble, headerJson, ...staged.map((s) => s.data), footer]);","handlingStrategy":"validation","validationCode":"const headerLen = buf.readUInt32LE(8);\nconst header = JSON.parse(buf.subarray(12, 12 + headerLen).toString('utf8'));\nconst maxEnd = Math.max(0, ...header.sections.map((s: any) => s.offset + s.size));\nif (maxEnd > buf.length - 32) throw new Error('image truncated — re-fetch');","typeGuard":null,"tryCatchPattern":"try { reader = RvfaReader.fromBuffer(buf); }\ncatch (e) {\n  if (/extends beyond buffer/.test(String((e as Error).message))) {\n    // re-download / rebuild; the bytes after the header are short\n  }\n  throw e;\n}","preventionTips":["Check free disk space before building/writing images","Concatenate ALL staged section payloads before the footer in build steps","Checksum artifacts end-to-end so truncation is caught at transfer"],"tags":["rvfa","truncated-file","buffer-bounds","binary-format"],"backgroundTag":"truncated-file","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}