gchq/CyberChef · error · OperationError

Invalid Bech32 string: no separator '1' found.

Error message

Invalid Bech32 string: no separator '1' found.

What it means

Thrown by decode() in src/core/lib/Bech32.mjs:260 when the input contains no '1' character at all, found via str.lastIndexOf('1') === -1. In Bech32 the '1' is the separator between the HRP and the data+checksum part; its absence means the structure of the string is unrecognisable. Note the separator search is case-sensitive but runs after lowercasing, and '1' is also a valid data character, so lastIndexOf finds the rightmost occurrence.

Source

Thrown at src/core/lib/Bech32.mjs:260

    // Check maximum length
    if (str.length > 90) {
        throw new OperationError(`Invalid Bech32 string: exceeds maximum length of 90 characters (got ${str.length}).`);
    }

    // Check for mixed case
    const hasUpper = /[A-Z]/.test(str);
    const hasLower = /[a-z]/.test(str);
    if (hasUpper && hasLower) {
        throw new OperationError("Invalid Bech32 string: mixed case is not allowed. Use all uppercase or all lowercase.");
    }

    // Convert to lowercase for processing
    str = str.toLowerCase();

    // Find separator (last occurrence of '1')
    const sepIndex = str.lastIndexOf("1");
    if (sepIndex === -1) {
        throw new OperationError("Invalid Bech32 string: no separator '1' found.");
    }

    if (sepIndex === 0) {
        throw new OperationError("Invalid Bech32 string: Human-Readable Part (HRP) cannot be empty.");
    }

    if (sepIndex + 7 > str.length) {
        throw new OperationError("Invalid Bech32 string: data part is too short (minimum 6 characters for checksum).");
    }

    // Extract HRP and data part
    const hrp = str.substring(0, sepIndex);
    const dataPart = str.substring(sepIndex + 1);

    // Validate HRP characters
    for (let i = 0; i < hrp.length; i++) {
        const c = hrp.charCodeAt(i);
        if (c < 33 || c > 126) {

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Confirm the input is actually Bech32/Bech32m (native SegWit) and not a legacy Base58 address.
  2. If the address was edited, restore the separator '1' between HRP and data.
  3. Detect format before decoding and route Base58 to a Base58 decoder.
  4. Check str.includes('1') before calling decode and give a clear error.

Example fix

// before - legacy Base58 address has no Bech32 separator
decode(base58Address);

// after - route by format
if (base58Address.startsWith('bc1') || base58Address.includes('1') /* bech32-ish */) {
  decode(base58Address);
} else {
  decodeBase58(base58Address); // legacy path
}
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeBech32(str) {
  return typeof str === 'string' && str.lastIndexOf('1') !== -1;
}
// if (!looksLikeBech32(input)) route to a Base58 decoder

Type guard

function hasBech32Separator(s) {
  return typeof s === 'string' && s.includes('1');
}

Try / catch

try {
  decode(input);
} catch (e) {
  if (e instanceof OperationError && /no separator '1' found/.test(e.message)) {
    // input is probably not Bech32; try legacy Base58
  }
}

Prevention

When it happens

Trigger: decode('bcrtq...') with no '1' anywhere; decode of a hex string, Base58 address, or other format that happens to contain no '1'. Also a Bech32 string where the separator was stripped or replaced.

Common situations: Decoding a Base58 (legacy Bitcoin) address which has no positional '1' separator; feeding raw hex; a mangled address where '1' was deleted; HRP-only string with no data part and no separator.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/ea2bf0e4c48a62fd. Report an issue: GitHub.