ruvnet/ruflo · error
String length exceeds remaining buffer
Error message
String length ${len} exceeds remaining buffer What it means
BufferReader.readString decodes a GGUF string as [u64 length][utf-8 bytes]; if the declared length exceeds the bytes remaining in the buffer, it throws rather than reading past the end. parseGgufHeader only reads the first 256 KB of the file, so this fires on truncated/corrupt files, headers whose metadata exceeds that window, or a reader desynchronized by an earlier malformed field.
Solutions
- Verify the file size and re-download/restore the model (compare checksums if the source publishes them)
- Check the magic and version first so corrupt files fail fast with a clearer error
- If large metadata is expected, read a bigger prefix than 256 KB before parsing
- Keep the reader aligned: treat unknown value types as fatal instead of skipping bytes
Defensive patterns
Strategy: try-catch
Validate before calling
const { size } = await stat(modelPath);
if (size < 4096) throw new Error(`model file suspiciously small: ${size} bytes`);
// magic/version pre-check also keeps the reader aligned
const meta = await parseGgufHeader(modelPath); Try / catch
try { meta = await parseGgufHeader(path); }
catch (e) { if (e instanceof Error && /String length|GGUF/.test(e.message)) { rejectModel(path, e.message); } else throw e; } Prevention
- Verify downloads with checksums before parsing
- Reject unknown value types fatally so the reader never desyncs mid-metadata
- Keep a size floor sanity check before parsing model files
When it happens
Trigger: parseGgufHeader on a partially downloaded .gguf; a model whose metadata block is larger than the 256 KB read window; buffer misalignment after an unknown value type consumed the wrong byte count; a non-GGUF binary that happened to pass the magic check.
Common situations: Interrupted downloads of multi-GB models; git-lfs pointer files fetched as raw bytes; files from converters emitting non-standard metadata ordering.
Related errors
- Unknown GGUF array element type
- Unknown GGUF value type
- Invalid GGUF magic: 0x
- KV cache file too small
- KV cache file truncated
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b7242bbcdd139014.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:99
readU8(): number { const v = this.buf.readUInt8(this.offset); this.offset += 1; return v; }
readI8(): number { const v = this.buf.readInt8(this.offset); this.offset += 1; return v; }
readU16(): number { const v = this.buf.readUInt16LE(this.offset); this.offset += 2; return v; }
readI16(): number { const v = this.buf.readInt16LE(this.offset); this.offset += 2; return v; }
readU32(): number { const v = this.buf.readUInt32LE(this.offset); this.offset += 4; return v; }
readI32(): number { const v = this.buf.readInt32LE(this.offset); this.offset += 4; return v; }
readF32(): number { const v = this.buf.readFloatLE(this.offset); this.offset += 4; return v; }
readF64(): number { const v = this.buf.readDoubleLE(this.offset); this.offset += 8; return v; }
readU64(): bigint { const v = this.buf.readBigUInt64LE(this.offset); this.offset += 8; return v; }
readI64(): bigint { const v = this.buf.readBigInt64LE(this.offset); this.offset += 8; return v; }
/** Safe for values up to 2^53. Real GGUF files never exceed this for tensor/kv counts. */
readU64AsNumber(): number { return Number(this.readU64()); }
readBool(): boolean { return this.readU8() !== 0; }
/** GGUF string: [length u64 LE][utf-8 bytes]. */
readString(): string {
const len = this.readU64AsNumber();
if (len === 0) return '';
if (len > this.remaining) throw new Error(`String length ${len} exceeds remaining buffer`);
const s = this.buf.toString('utf-8', this.offset, this.offset + len);
this.offset += len;
return s;
}
}
// ── GGUF Value Reading ──────────────────────────────────────
/** Read a typed scalar from the buffer (shared by value and array-element readers). */
function readScalar(reader: BufferReader, t: number): unknown {
switch (t) {
case GgufValueType.UINT8: return reader.readU8();
case GgufValueType.INT8: return reader.readI8();
case GgufValueType.UINT16: return reader.readU16();
case GgufValueType.INT16: return reader.readI16();
case GgufValueType.UINT32: return reader.readU32();
case GgufValueType.INT32: return reader.readI32();
case GgufValueType.FLOAT32: return reader.readF32();View on GitHub (pinned to fa13ee4ad6)