gchq/CyberChef · error · OperationError

Invalid Bech32 string: mixed case is not allowed. Use all up

Error message

Invalid Bech32 string: mixed case is not allowed. Use all uppercase or all lowercase.

What it means

Thrown by decode() in src/core/lib/Bech32.mjs:251 when the input contains both uppercase (A-Z) and lowercase (a-z) letters. BIP-0173 forbids mixed case: a Bech32 string must be entirely uppercase or entirely lowercase so that case-insensitive comparison is unambiguous. The check uses /[A-Z]/ and /[a-z]/ regexes; if both match, the string is invalid regardless of correctness.

Source

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

 * @param {string} encoding - "Bech32", "Bech32m", or "Auto-detect"
 * @returns {{hrp: string, data: number[]}} - Decoded HRP and data bytes
 */
export function decode(str, encoding = "Auto-detect") {
    // Check for empty input
    if (!str || str.length === 0) {
        throw new OperationError("Input cannot be empty.");
    }

    // 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).");
    }

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Normalize the whole string to one case before decoding: str.toLowerCase() or str.toUpperCase().
  2. Disable auto-capitalization on input fields that accept addresses.
  3. Validate case consistency before submitting and warn the user.
  4. If normalizing changes the address, treat it as the canonical form (Bech32 case is not semantically significant).

Example fix

// before - mixed case
decode(userInput); // 'Bc1QAb...'

// after - normalize to lowercase
decode(userInput.toLowerCase());
Defensive patterns

Strategy: validation

Validate before calling

function normalizeBech32Case(str) {
  const hasUpper = /[A-Z]/.test(str);
  const hasLower = /[a-z]/.test(str);
  if (hasUpper && hasLower) return str.toLowerCase(); // or toUpperCase
  return str;
}

Type guard

function isSingleCase(s) {
  return typeof s === 'string' && !(/[A-Z]/.test(s) && /[a-z]/.test(s));
}

Try / catch

try {
  decode(input);
} catch (e) {
  if (e instanceof OperationError && /mixed case/.test(e.message)) {
    input = input.toLowerCase(); // canonical fix
  }
}

Prevention

When it happens

Trigger: decode('bc1qABcDeFgH...') where some letters are upper and some lower. Happens when auto-correct or a title-case formatter touched the address, or when an uppercase address was partially lowercased.

Common situations: Mobile keyboards auto-capitalizing the first letter; copy-paste through a tool that title-cased the string; user manually edited part of the address; QR-code decoders that normalize case inconsistently.

Related errors


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