{"record":{"id":"615227fc6dc3d697","repo":"gchq/CyberChef","slug":"hrp-contains-invalid-character-at-position-i-o","errorCode":null,"errorMessage":"HRP contains invalid character at position ${i}. Only printable ASCII characters (33-126) are allowed.","messagePattern":"HRP contains invalid character at position (.+?)\\. Only printable ASCII characters \\(33-126\\) are allowed\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/Bech32.mjs","lineNumber":181,"sourceCode":" * Encode data to Bech32/Bech32m string\n *\n * @param {string} hrp - Human-readable part\n * @param {number[]|Uint8Array} data - Data bytes to encode\n * @param {string} encoding - \"Bech32\" or \"Bech32m\"\n * @param {boolean} segwit - If true, treat first byte as witness version (for Bitcoin SegWit)\n * @returns {string} - Encoded Bech32/Bech32m string\n */\nexport function encode(hrp, data, encoding = \"Bech32\", segwit = false) {\n    // Validate HRP\n    if (!hrp || hrp.length === 0) {\n        throw new OperationError(\"Human-Readable Part (HRP) cannot be empty.\");\n    }\n\n    // Check HRP characters (ASCII 33-126)\n    for (let i = 0; i < hrp.length; i++) {\n        const c = hrp.charCodeAt(i);\n        if (c < 33 || c > 126) {\n            throw new OperationError(`HRP contains invalid character at position ${i}. Only printable ASCII characters (33-126) are allowed.`);\n        }\n    }\n\n    // Convert HRP to lowercase\n    const hrpLower = hrp.toLowerCase();\n\n    let words;\n    if (segwit && data.length >= 2) {\n        // SegWit encoding: first byte is witness version (0-16), rest is witness program\n        const witnessVersion = data[0];\n        if (witnessVersion > 16) {\n            throw new OperationError(`Invalid witness version: ${witnessVersion}. Must be 0-16.`);\n        }\n        const witnessProgram = Array.prototype.slice.call(data, 1);\n\n        // Validate witness program length per BIP-0141\n        if (witnessProgram.length < 2 || witnessProgram.length > 40) {\n            throw new OperationError(`Invalid witness program length: ${witnessProgram.length}. Must be 2-40 bytes.`);","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/Bech32.mjs#L163-L199","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before - trailing newline in config HRP\nencode(hrp + '\\n', program, 'Bech32', true);\n\n// after - sanitize the HRP\nconst cleanHrp = hrp.replace(/[^\\x21-\\x7e]/g, '');\nencode(cleanHrp, program, 'Bech32', true);","handlingStrategy":"validation","validationCode":"function sanitizeHrp(hrp) {\n  if (typeof hrp !== 'string') throw new TypeError('HRP must be a string');\n  return hrp.replace(/[^\\x21-\\x7e]/g, '');\n}","typeGuard":"function isValidHrp(hrp) {\n  if (typeof hrp !== 'string' || hrp.length === 0) return false;\n  for (let i = 0; i < hrp.length; i++) {\n    const c = hrp.charCodeAt(i);\n    if (c < 33 || c > 126) return false;\n  }\n  return true;\n}","tryCatchPattern":"try {\n  encode(hrp, data, 'Bech32', true);\n} catch (e) {\n  if (e instanceof OperationError && /HRP contains invalid character/.test(e.message)) {\n    hrp = hrp.replace(/[^\\x21-\\x7e]/g, '');\n  }\n}","preventionTips":["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."],"tags":["bech32","encoding","hrp","ascii","input-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}