gchq/CyberChef · error · OperationError
HRP contains invalid character at position ${i}. Only printa
Error message
HRP contains invalid character at position ${i}. Only printable ASCII characters (33-126) are allowed. What it means
Thrown by encode() in src/core/lib/Bech32.mjs:181 when any character of the HRP falls outside ASCII range 33-126 (printable, excluding space). BIP-0173 restricts the HRP to ASCII 33-126; spaces, control characters, DEL, and any non-ASCII (UTF-8 multibyte) character are forbidden because they would break case-folding and checksum portability.
Source
Thrown at src/core/lib/Bech32.mjs:181
* Encode data to Bech32/Bech32m string
*
* @param {string} hrp - Human-readable part
* @param {number[]|Uint8Array} data - Data bytes to encode
* @param {string} encoding - "Bech32" or "Bech32m"
* @param {boolean} segwit - If true, treat first byte as witness version (for Bitcoin SegWit)
* @returns {string} - Encoded Bech32/Bech32m string
*/
export function encode(hrp, data, encoding = "Bech32", segwit = false) {
// Validate HRP
if (!hrp || hrp.length === 0) {
throw new OperationError("Human-Readable Part (HRP) cannot be empty.");
}
// Check HRP characters (ASCII 33-126)
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}. Only printable ASCII characters (33-126) are allowed.`);
}
}
// Convert HRP to lowercase
const hrpLower = hrp.toLowerCase();
let words;
if (segwit && data.length >= 2) {
// SegWit encoding: first byte is witness version (0-16), rest is witness program
const witnessVersion = data[0];
if (witnessVersion > 16) {
throw new OperationError(`Invalid witness version: ${witnessVersion}. Must be 0-16.`);
}
const witnessProgram = Array.prototype.slice.call(data, 1);
// Validate witness program length per BIP-0141
if (witnessProgram.length < 2 || witnessProgram.length > 40) {
throw new OperationError(`Invalid witness program length: ${witnessProgram.length}. Must be 2-40 bytes.`);View on GitHub (pinned to 4290ea7539)
Solutions
- Trim whitespace and newlines from the HRP: hrp = hrp.trim().
- Restrict the HRP to the BIP-0173 character set before calling encode.
- Use a known-good HRP constant ('bc', 'tb', 'bcrt', 'ltc', etc.).
- If the HRP is user-supplied, validate each character is in 33-126 and surface a clear error.
Example fix
// before - trailing newline in config HRP encode(hrp + '\n', program, 'Bech32', true); // after - sanitize the HRP const cleanHrp = hrp.replace(/[^\x21-\x7e]/g, ''); encode(cleanHrp, program, 'Bech32', true);
Defensive patterns
Strategy: validation
Validate before calling
function sanitizeHrp(hrp) {
if (typeof hrp !== 'string') throw new TypeError('HRP must be a string');
return hrp.replace(/[^\x21-\x7e]/g, '');
} Type guard
function isValidHrp(hrp) {
if (typeof hrp !== 'string' || hrp.length === 0) return false;
for (let i = 0; i < hrp.length; i++) {
const c = hrp.charCodeAt(i);
if (c < 33 || c > 126) return false;
}
return true;
} Try / catch
try {
encode(hrp, data, 'Bech32', true);
} catch (e) {
if (e instanceof OperationError && /HRP contains invalid character/.test(e.message)) {
hrp = hrp.replace(/[^\x21-\x7e]/g, '');
}
} Prevention
- Trim whitespace and newlines from any config-supplied HRP.
- Use a constant HRP for your network instead of building it from user text.
- Reject non-ASCII HRPs at the input boundary.
When it happens
Trigger: encode('b c', data) (space, code 32 < 33), encode('b\u0000c', data) (null byte), encode('bérica', data) (non-ASCII), encode('bc\n', data) (trailing newline). Any HRP containing a character whose charCodeAt is < 33 or > 126.
Common situations: Trailing newline or whitespace in a config-supplied HRP; copy-paste of an HRP that included a space; using a localized/non-Latin HRP; accidentally passing the full address string as the HRP.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Human-Readable Part (HRP) cannot be empty.
- Encoded string exceeds maximum length of 90 characters (got
- Invalid Bech32 string: Human-Readable Part (HRP) cannot be e
- Invalid value
- Invalid padding: too many bits remaining
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/615227fc6dc3d697.
Report an issue: GitHub.