gchq/CyberChef · error · OperationError

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

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.

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.

Appendix: 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)