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
- Confirm the input is actually Bech32/Bech32m (native SegWit) and not a legacy Base58 address.
- If the address was edited, restore the separator '1' between HRP and data.
- Detect format before decoding and route Base58 to a Base58 decoder.
- 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
- Detect address format before choosing a decoder.
- Bech32 native SegWit addresses start with a known HRP + '1' (e.g. 'bc1').
- Do not feed legacy Base58 addresses into the Bech32 decoder.
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
- Invalid Bech32 string: Human-Readable Part (HRP) cannot be e
- Invalid padding: too many bits remaining
- Input cannot be empty.
- Invalid Bech32 string: exceeds maximum length of 90 characte
- Invalid Bech32 string: mixed case is not allowed. Use all up
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/ea2bf0e4c48a62fd.
Report an issue: GitHub.