bytedance/deer-flow · error · ValueError

expected 32-byte payload in {value!r}

Error message

expected 32-byte payload in {value!r}

What it means

After a valid checksum, the bech32 data part is converted from 5-bit groups back to bytes; the decoder requires exactly 32 bytes because Nostr keys are 32-byte values. If the decoded length differs (too short/long), this ValueError is raised — a structurally valid bech32 string of the wrong length, which for real nsec/npub keys should never happen.

Source

Thrown at backend/app/channels/buzz_nostr.py:67

    if hrp != expected_hrp:
        raise ValueError(f"expected {expected_hrp!r} bech32, got {hrp!r}")
    try:
        data = [_BECH32_CHARSET.index(c) for c in data_part]
    except ValueError as exc:
        raise ValueError(f"invalid bech32 character in {value!r}") from exc
    hrp_expanded = [ord(c) >> 5 for c in hrp] + [0] + [ord(c) & 31 for c in hrp]
    if _bech32_polymod(hrp_expanded + data) != 1:
        raise ValueError(f"bad bech32 checksum in {value!r}")
    acc = bits = 0
    out = bytearray()
    for v in data[:-6]:
        acc = (acc << 5) | v
        bits += 5
        if bits >= 8:
            bits -= 8
            out.append((acc >> bits) & 0xFF)
    if len(out) != 32:
        raise ValueError(f"expected 32-byte payload in {value!r}")
    return bytes(out)


def _parse_32_bytes(value: str, bech_hrp: str) -> bytes:
    value = value.strip()
    if value.lower().startswith(f"{bech_hrp}1"):
        return _bech32_decode(bech_hrp, value.lower())
    try:
        raw = bytes.fromhex(value)
    except ValueError as exc:
        raise ValueError(f"expected 64-hex or {bech_hrp}1... value") from exc
    if len(raw) != 32:
        raise ValueError("expected exactly 32 bytes")
    return raw


def parse_private_key(value: str) -> NostrKeys:
    secret = _parse_32_bytes(value, "nsec")

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Generate the key with a standard Nostr client or `python -c "import secrets; print(secrets.token_hex(32))"` and use the hex form.
  2. Do not hand-craft or modify bech32 strings.
  3. If a tool produced this value, report the encoding bug to that tool and re-export the key.

Example fix

# generate a fresh key as hex and use it directly
python -c "import secrets; print(secrets.token_hex(32))"
# -> put the 64-char hex output into channels.buzz.private_key
Defensive patterns

Strategy: validation

Validate before calling

def is_32byte_bech32(value: str, hrp: str) -> bool:
    v = value.strip().lower()
    if not (v.startswith(hrp + '1') and '1' in v[len(hrp) + 1:]):
        return False
    data_len = len(v.rsplit('1', 1)[-1]) - 6  # minus checksum
    return data_len * 5 // 8 == 32

Try / catch

try:
    keys = parse_private_key(raw)
except ValueError:
    # generate a fresh, known-good key rather than debugging a hand-made one
    raw = secrets.token_hex(32)
    keys = parse_private_key(raw)

Prevention

When it happens

Trigger: A bech32 string with a correct checksum but a payload that decodes to something other than 32 bytes — typically a hand-crafted value, a key from a different scheme that happens to carry the nsec/npub hrp, or a value padded/extended in a checksum-consistent way.

Common situations: Very rare in practice; usually indicates someone generated a test/garbage value, or a tool emitted a non-standard encoding. Real nsec1/npub1 keys from any Nostr client are always 32 bytes.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/72caba71453ee6e7. Report an issue: GitHub.