bytedance/deer-flow · error · ValueError

invalid bech32 character in {value!r}

Error message

invalid bech32 character in {value!r}

What it means

The bech32 data part must consist only of characters from the 32-character bech32 charset 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'. If any character after the separator is not in that set (e.g. 'b', 'i', 'o', digits like '1' inside data, uppercase mix issues aside), list.index raises ValueError and the decoder re-raises with this message.

Source

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

    chk = 1
    for v in values:
        b = chk >> 25
        chk = (chk & 0x1FFFFFF) << 5 ^ v
        for i in range(5):
            chk ^= gen[i] if ((b >> i) & 1) else 0
    return chk


def _bech32_decode(expected_hrp: str, value: str) -> bytes:
    if "1" not in value:
        raise ValueError(f"not bech32: {value!r}")
    hrp, data_part = value.rsplit("1", 1)
    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()

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Re-copy the key carefully from the source; bech32 data parts exclude '1', 'b', 'i', 'o'.
  2. Ensure the value in config.yaml is a single quoted string with no embedded newlines.
  3. Validate the key in a Nostr client first — if the client also rejects it, the key itself is corrupted.
  4. Prefer pasting the 64-hex-char form, which avoids bech32 entirely.

Example fix

# before (contains invalid 'b' and a newline)
private_key: "nsec1abc
defb..."

# after (single line, valid charset)
private_key: "nsec1qpzry9x8gf2tvdw0s3jn54khce6mua7..."
Defensive patterns

Strategy: validation

Validate before calling

BECH32_CHARSET = set('qpzry9x8gf2tvdw0s3jn54khce6mua7l')

def charset_ok(value: str, hrp: str) -> bool:
    data = value.strip().lower().rsplit('1', 1)[-1]
    return bool(data) and all(c in BECH32_CHARSET for c in data)

Try / catch

try:
    _parse_32_bytes(value, 'nsec')
except ValueError as e:
    logger.warning('rejecting malformed buzz key (%s)', type(e).__name__)
    raise

Prevention

When it happens

Trigger: A corrupted or hand-edited key containing invalid characters — e.g. a base58 character ('b', 'i', 'o', '1') in the data part, or an HTML-escaped/truncated paste that introduced stray characters after the '1' separator.

Common situations: Key mangled by YAML quoting/escaping; terminal copy that swallowed characters and the user re-typed part of it; pasting a key with line-wrapping newlines embedded inside; OCR of a key.

Related errors


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