ruvnet/ruflo · error
Section " " exceeds buffer bounds
Error message
Section "${id}" exceeds buffer bounds What it means
extractSection(id) re-checks at read time that sec.offset + sec.size <= buf.length - 32, even though fromBuffer already validated this. It fires when the buffer shrank between construction and extraction — e.g. the caller passed a subarray/truncated copy — or when a RvfaReader was somehow constructed without full validation. It is defense-in-depth against reading past the data region into the SHA256 footer.
Solutions
- Always obtain readers via RvfaReader.fromBuffer(buf) or await RvfaReader.fromFile(path) — both run the full validation pass
- Don't share or mutate the buffer you passed to fromBuffer; the reader retains a reference (subarray shares memory)
- If you must revalidate, rebuild the reader from the original full buffer rather than patching offsets
- Add an assertion on buf.length before extractSection in hot paths to catch early buffer swaps
Example fix
// before — reusing a reader after truncating the source buffer
const reader = RvfaReader.fromBuffer(buf);
buf = buf.subarray(0, 1000); // reader still points at original, sizes now wrong
reader.extractSection('kernel');
// after — rebuild the reader from the bytes you actually have
const reader = RvfaReader.fromBuffer(buf);
// ... later, if buf changed:
const fresh = RvfaReader.fromBuffer(currentBuf); Defensive patterns
Strategy: validation
Validate before calling
const sec = reader.getSections().find((s) => s.id === id);
if (!sec || sec.offset + sec.size > buf.length - 32) {
throw new Error('section would read past data region — buffer changed');
} Try / catch
try { const data = reader.extractSection(id); }
catch (e) {
if (/exceeds buffer bounds/.test(String((e as Error).message))) {
// rebuild the reader from the full original buffer
}
throw e;
} Prevention
- Only obtain readers via fromBuffer/fromFile — never construct them directly
- Do not mutate or shrink the buffer passed to fromBuffer (subarray shares memory)
- Rebuild the reader instead of patching buffers when underlying data changes
When it happens
Trigger: Calling extractSection after the reader's underlying buffer was replaced or the reader was built via a path that skipped validation; or holding a reader over a Buffer that a debugging step reallocated. In normal use (fromBuffer/fromFile) this is unreachable — seeing it means the reader instance was constructed unusually or the buffer was mutated.
Common situations: Test code constructing RvfaReader-like objects directly; buffer pooling/copying bugs where a smaller buffer is handed to an existing reader; memory-pressure 'optimizations' that slice buffers in place.
Related errors
- Buffer too small to contain declared header
- Section " " extends beyond buffer (offset= , size= …
- Buffer too small to be a valid RVFA file
- Buffer too small to contain RVFA preamble
- Failed to parse RVFA header JSON
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/85194a5650b41e23.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/rvfa-format.ts:416
/** List all sections declared in the header. */
getSections(): RvfaSection[] {
return this.header.sections;
}
/**
* Extract and decompress a section by its id.
*
* @param id The section identifier (e.g. 'kernel', 'runtime').
* @returns The decompressed section payload.
*/
extractSection(id: string): Buffer {
const sec = this.header.sections.find((s) => s.id === id);
if (!sec) {
throw new Error(`Section "${id}" not found`);
}
if (sec.offset + sec.size > this.buf.length - SHA256_SIZE) {
throw new Error(`Section "${id}" exceeds buffer bounds`);
}
const raw = this.buf.subarray(sec.offset, sec.offset + sec.size);
if (sec.compression === 'gzip') {
return gunzipSync(raw);
}
if (sec.compression === 'zstd') {
// zstd not natively supported — attempt gzip fallback (mirrors writer)
try {
return gunzipSync(raw);
} catch {
throw new Error(
'zstd decompression is not supported in this environment',
);
}
}
View on GitHub (pinned to fa13ee4ad6)