gchq/CyberChef · error · OperationError

Invalid Bech32 string: Human-Readable Part (HRP) cannot be e

Error message

Invalid Bech32 string: Human-Readable Part (HRP) cannot be empty.

What it means

Thrown by decode() in src/core/lib/Bech32.mjs:264 when the rightmost '1' separator is at index 0 — meaning nothing precedes it and the HRP is empty. This is the decode-side counterpart of the encode-side empty-HRP guard; an empty HRP makes checksum verification meaningless because the HRP contributes to polymod via hrpExpand.

Source

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

    // 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) {
            throw new OperationError(`HRP contains invalid character at position ${i}.`);
        }
    }

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Pass the complete Bech32 string including its HRP prefix (e.g. 'bc1q...').
  2. If the HRP was stripped, re-prepend the correct HRP and '1' before decoding.
  3. Validate that the string starts with a known HRP ('bc', 'tb', 'bcrt', etc.) before decoding.
  4. Audit any pre-processing that might have truncated the prefix.

Example fix

// before - HRP stripped, separator at index 0
decode('1qwl3q4l');

// after - include the HRP
decode('bc1qwl3q4l...');
Defensive patterns

Strategy: validation

Validate before calling

function requireHrpPrefix(str) {
  const sep = str.lastIndexOf('1');
  if (sep <= 0) throw new Error('Bech32 string missing HRP before separator');
  return str;
}

Type guard

function hasNonEmptyHrpBeforeSeparator(s) {
  const i = typeof s === 'string' ? s.lastIndexOf('1') : -1;
  return i > 0;
}

Try / catch

try {
  decode(input);
} catch (e) {
  if (e instanceof OperationError && /HRP.*cannot be empty/.test(e.message)) {
    // re-prepend the correct HRP + '1'
  }
}

Prevention

When it happens

Trigger: decode('1qwerty...') where the string starts with '1'. Reached after the separator is found (sepIndex !== -1) but equals zero. Happens when the HRP was stripped, leaving the separator as the first character.

Common situations: User pasted only the data+checksum part without the HRP; a regex or formatter deleted the HRP prefix; an address from a chain whose HRP the user removed expecting it to be implicit; confused variable holding dataPart instead of the full string.

Related errors


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