{"record":{"id":"f876fa1c26f54bab","repo":"NousResearch/hermes-agent","slug":"loadout-truncated","errorCode":null,"errorMessage":"loadout truncated","messagePattern":"loadout truncated","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"apps/desktop/src/lib/loadout.ts","lineNumber":74,"sourceCode":"\n    for (let i = 0; i < this.bits.length; i += 1) {\n      if (this.bits[i]) {\n        out[i >> 3]! |= 1 << (i & 7)\n      }\n    }\n\n    return out\n  }\n}\n\nexport class BitReader {\n  private pos = 0\n\n  constructor(private readonly buf: Uint8Array) {}\n\n  bit(): number {\n    if (this.pos >= this.buf.length * 8) {\n      throw new RangeError('loadout truncated')\n    }\n\n    const i = this.pos++\n\n    return (this.buf[i >> 3]! >> (i & 7)) & 1\n  }\n\n  uint(width: number): number {\n    let v = 0\n\n    for (let i = 0; i < width; i += 1) {\n      v |= this.bit() << i\n    }\n\n    return v >>> 0\n  }\n\n  varint(): number {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/src/lib/loadout.ts#L56-L92","documentation":"A RangeError thrown by BitReader.bit() in apps/desktop/src/lib/loadout.ts:74 when a loadout decode reads past the end of the byte buffer — the bit position reached or exceeded buf.length*8. Loadout codes are bit-packed, DEFLATE-compressed payloads; the reader has no length-prefixed bound per field, so a structurally-short payload (or a read schema that disagrees with the write schema) runs off the end. The top-level decode() wraps schema-read failures as '<Noun> is malformed: ...', so end users usually see the wrapped form; 'loadout truncated' surfaces raw when BitReader is used directly.","triggerScenarios":"spec.read() calling uint/varint/str more times or with wider fields than spec.write() emitted; a payload sliced short (decode called on framed bytes shorter than the writer produced); version mismatch that changed field widths; manually constructing BitReader over a truncated subarray (e.g. wrong HEAD_BYTES split).","commonSituations":"Editing a loadout schema (adding a field) without bumping spec.version, so old codes decode with the new reader; a copy/paste of a share code that lost characters but still base64-decodes; hand-rolled framing changes; tests constructing readers from arbitrary buffers.","solutions":["Bump spec.version whenever the bit layout changes, so old codes fail the version check instead of reading off the end.","Audit spec.read to consume exactly what spec.write emits (same fields, same widths, same order, varint/str pairs).","If decoding user-pasted codes, rely on createLoadout's decode() which converts this into the friendly 'malformed' Err.","When framing manually, slice with the correct header size before handing bytes to BitReader."],"exampleFix":"// before — reader out of sync with writer\nwrite: w => { w.uint(mode, 2) }\nread: r => ({ mode: r.uint(4) }) // reads too many bits -> truncated on short payloads\n\n// after — symmetric widths + version bump on any layout change\nwrite: w => { w.uint(mode, 2) }\nread: r => ({ mode: r.uint(2) })","handlingStrategy":"validation","validationCode":"// round-trip property test: decode(encode(x)) deep-equals x\nconst sample = makeRepresentativePayload()\nconst code = encode(sample)\nconst back = decode(code)\nassert.deepEqual(back, sample) // catches reader/writer asymmetry before users do","typeGuard":null,"tryCatchPattern":"try {\n  return spec.read(new BitReader(inflateSync(payload)))\n} catch (err) {\n  if (err instanceof RangeError && err.message === 'loadout truncated') throw new Err('Schema read ran past the payload — read/write asymmetry or truncated data')\n  throw err\n}","preventionTips":["Bump spec.version with EVERY bit-layout change","Keep spec.read the exact mirror of spec.write (order, widths, varint/str pairs)","Always frame with the codec's encode()/decode(); never hand-slice buffers for BitReader","Round-trip test every schema change with edge-case payloads"],"tags":["desktop","loadout","binary","codec","range-error"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}