bytedance/deer-flow · error · ValueError
not bech32: {value!r}
Error message
not bech32: {value!r} What it means
Part of the minimal bech32 decoder used for Nostr nsec/npub keys: _bech32_decode requires a '1' separator between the human-readable part (hrp) and the data part. If the input contains no '1' at all, it cannot even be split, so this ValueError is raised. nsec/npub keys always look like <hrp>1<data>.
Source
Thrown at backend/app/channels/buzz_nostr.py:47
class NostrKeys:
secret: bytes
pubkey_hex: str
def _bech32_polymod(values: list[int]) -> int:
gen = [0x3B6A57B2, 0x26508E6D, 0x1EA119FA, 0x3D4233DD, 0x2A1462B3]
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)View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Re-copy the full key from your Nostr wallet/client; nsec1... and npub1... always contain a '1' right after the prefix.
- Prefer pasting the raw 64-char hex secret instead — _parse_32_bytes also accepts plain hex.
- Check for truncation or invisible characters; the value is used as-is after strip().
- Never commit the fixed key — rotate it if it was logged.
Example fix
# before
channels:
buzz:
private_key: "nsec"
# after (full key or hex)
channels:
buzz:
private_key: "nsec1<full-data-part>" Defensive patterns
Strategy: validation
Validate before calling
def looks_bech32(value: str, hrp: str) -> bool:
v = value.strip().lower()
return v.startswith(hrp) and '1' in v[len(hrp):] Try / catch
try:
keys = parse_private_key(raw)
except ValueError as e:
raise SystemExit(f'bad buzz private_key: {e}') from e Prevention
- Validate nsec/npub values at config load time, not at first use.
- Prefer hex-form keys in automated setups to avoid bech32 edge cases.
- Test key parsing in CI with known-good fixtures.
When it happens
Trigger: channels.buzz config passes a value to parse_private_key/parse_pubkey that starts with 'nsec'/'npub' (or is detected as bech32) but has no '1' separator — e.g. 'nsec', 'npubXYZ', or a truncated key pasted without its data part.
Common situations: Copy-paste of a Nostr key that got truncated; typing a key by hand; pasting a hex key with a stray 'nsec' prefix glued on; whitespace-only partial values after strip().
Related errors
- expected {expected_hrp!r} bech32, got {hrp!r}
- invalid bech32 character in {value!r}
- bad bech32 checksum in {value!r}
- expected 32-byte payload in {value!r}
- expected 64-hex or {bech_hrp}1... value
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/3653fa5b0e2bdb3d.
Report an issue: GitHub.