NousResearch/hermes-agent · warning · LoadoutError

${Noun} is malformed: ${err.message}

Error message

${Noun} is malformed: ${err.message}

What it means

Thrown by the loadout codec's decode() in apps/desktop/src/lib/loadout.ts:274 when the payload passes version and checksum but fails during inflation (inflateSync) or schema reading (spec.read over BitReader) — the exception's message is appended as '<Noun> is malformed: <reason>'. This catches payloads that are structurally intact per the frame but semantically broken: invalid DEFLATE streams, bit-reads running past the end ('loadout truncated' RangeError gets wrapped here), or schema-level constraint violations inside spec.read.

Source

Thrown at apps/desktop/src/lib/loadout.ts:274

    const head = new BitReader(framed.subarray(0, HEAD_BYTES))
    const version = head.uint(8)
    const storedSum = head.uint(16)

    if (version !== spec.version) {
      throw new Err(`${Noun} is version ${version}; this build reads version ${spec.version}.`)
    }

    const payload = framed.subarray(HEAD_BYTES)

    if (checksum16(payload) !== storedSum) {
      throw new Err(`${Noun} looks corrupted (checksum mismatch).`)
    }

    try {
      return spec.read(new BitReader(inflateSync(payload)))
    } catch (err) {
      throw new Err(err instanceof Error ? `${Noun} is malformed: ${err.message}` : `${Noun} is malformed.`)
    }
  }

  return { decode, encode }
}

View on GitHub (pinned to c896c09c42)

Solutions

  1. Read the appended inner message — it identifies whether inflation or a specific schema read failed and usually names the field.
  2. Round-trip test encode()->decode() for every spec change; a malformed-code error from your own producer is a writer/reader asymmetry bug.
  3. Ensure spec.read validates its own invariants (throw with a descriptive message) so this error is precise.
  4. For user-pasted codes, request a fresh code; this stage means the bytes are self-consistent but wrong-shaped.

Example fix

// before — read consumes more than write emits (surfaces as 'malformed: loadout truncated')
write: (w, v) => { w.str(v.name) }
read: r => ({ name: r.str(), extra: r.uint(3) }) // extra never written

// after — symmetric schema
write: (w, v) => { w.str(v.name); w.uint(v.extra ?? 0, 3) }
read: r => ({ name: r.str(), extra: r.uint(3) })
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return spec.read(new BitReader(inflateSync(payload)))
} catch (err) {
  throw new Err(err instanceof Error ? `${Noun} is malformed: ${err.message}` : `${Noun} is malformed.`)
}
// callers: catch (e) { if (e instanceof Err && /malformed/.test(e.message)) requestFreshCode() }

Prevention

When it happens

Trigger: spec.read throwing its own validation errors (e.g. unknown enum id, out-of-range index); BitReader running off the end because read/write schemas disagree at the current version; inflateSync failing on a payload that checksummed correctly but was produced by a buggy writer.

Common situations: A producer bug writing fewer bits than read consumes while still bumping neither version nor catching the mismatch; schema changes shipped with a version bump but an asymmetric read; codes generated by experimental builds.

Understand the failure class

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/391e57c81692e3c9. Report an issue: GitHub.