bytedance/deer-flow · error · ValueError

expected 64-hex or {bech_hrp}1... value

Error message

expected 64-hex or {bech_hrp}1... value

What it means

_parse_32_bytes accepts either a bech32 value (hrp + '1' + data) or a raw hex string. If the input does not start with the expected hrp prefix, it falls back to bytes.fromhex(); when that raises ValueError (non-hex characters, odd length, or an empty string), this error listing both accepted forms is raised.

Source

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

    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")
    coincurve = _require_coincurve()
    pubkey = coincurve.PrivateKey(secret).public_key.format(compressed=True)[1:]
    return NostrKeys(secret=secret, pubkey_hex=pubkey.hex())


def parse_pubkey(value: str) -> str:
    return _parse_32_bytes(value, "npub").hex()


def event_id(pubkey_hex: str, created_at: int, kind: int, tags: list[list[str]], content: str) -> str:
    payload = json.dumps([0, pubkey_hex, created_at, kind, tags, content], separators=(",", ":"), ensure_ascii=False)

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Provide the key as either nsec1/npub1 bech32 or plain 64-character hex (no 0x prefix).
  2. Strip any '0x' prefix, quotes, or whitespace before pasting.
  3. If your source wallet only exports other formats, convert it to hex first with a key-conversion tool.

Example fix

# before
private_key: "0x4c0a5c..."   # 0x prefix is not hex for this parser

# after
private_key: "4c0a5c..."       # exactly 64 hex chars
Defensive patterns

Strategy: validation

Validate before calling

import re

def is_hex32(value: str) -> bool:
    v = value.strip().removeprefix('0x')
    return bool(re.fullmatch(r'[0-9a-fA-F]{64}', v))

def is_acceptable_key(value: str, hrp: str) -> bool:
    return value.strip().lower().startswith(hrp + '1') or is_hex32(value)

Try / catch

try:
    _parse_32_bytes(value, 'npub')
except ValueError as e:
    if '64-hex' in str(e):
        hint = 'expected nsec1/npub1 bech32 or 64-char hex (no 0x prefix)'
        raise ConfigError(f'{e}: {hint}') from e
    raise

Prevention

When it happens

Trigger: A value that is neither bech32 (does not start with nsec1/npub1) nor valid hex — e.g. a base64 key, a WIF string, a key with '0x' prefix, an empty string, or odd-length hex after paste truncation.

Common situations: Pasting a key exported in the wrong format (base64/WIF/0x-prefixed); empty config value reaching the parser; shell variable expansion mangling the key; using a key from a non-Nostr wallet.

Related errors


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