gchq/CyberChef · error · OperationError
Invalid witness program length for v0: ${witnessProgram.leng
Error message
Invalid witness program length for v0: ${witnessProgram.length}. Must be 20 or 32 bytes. What it means
Thrown by encode() in src/core/lib/Bech32.mjs:202 in SegWit mode when witnessVersion is 0 and the program length is neither 20 nor 32 bytes. BIP-0173 fixes v0 programs to exactly 20 bytes (P2WPKH, HASH160) or 32 bytes (P2WSH, SHA256); any other length for v0 is invalid and consensus-illegal, so the library refuses to produce an address that no node would accept.
Source
Thrown at src/core/lib/Bech32.mjs:202
// 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.`);
}
if (witnessVersion === 0 && witnessProgram.length !== 20 && witnessProgram.length !== 32) {
throw new OperationError(`Invalid witness program length for v0: ${witnessProgram.length}. Must be 20 or 32 bytes.`);
}
// Witness version is kept as single 5-bit value, program is converted
words = [witnessVersion].concat(toWords(witnessProgram));
} else {
// Generic encoding: convert all bytes to 5-bit words
words = toWords(data);
}
// Create checksum
const checksum = createChecksum(hrpLower, words, encoding);
// Build result string
let result = hrpLower + "1";
for (const w of words.concat(checksum)) {
result += CHARSET[w];
}
View on GitHub (pinned to 4290ea7539)
Solutions
- For P2WPKH (v0): use HASH160 (ripemd160(sha256(pubkey))) -> exactly 20 bytes.
- For P2WSH (v0): use SHA256 of the script -> exactly 32 bytes.
- If your program is a different length, use witness version 1+ (Taproot etc.) where 2-40 bytes are allowed.
- Re-derive the hash with the correct algorithm and verify the byte count before encoding.
Example fix
// before - v0 program is 21 bytes (invalid)
encode('bc', [0, ...hashWithExtraByte], 'Bech32', true);
// after - 20-byte HASH160 for P2WPKH
encode('bc', [0, ...ripemd160(sha256(pubkey))], 'Bech32', true); Defensive patterns
Strategy: validation
Validate before calling
function validateV0Program(program) {
if (program.length !== 20 && program.length !== 32) {
throw new RangeError(`v0 program must be 20 or 32 bytes, got ${program.length}`);
}
return program;
} Type guard
function isV0ProgramLength(bytes) {
return Array.isArray(bytes) && (bytes.length === 20 || bytes.length === 32);
} Try / catch
try {
encode('bc', [0, ...program], 'Bech32', true);
} catch (e) {
if (e instanceof OperationError && /witness program length for v0/.test(e.message)) {
// wrong hash function used; re-hash with HASH160 or SHA256
}
} Prevention
- P2WPKH: HASH160 (20 bytes). P2WSH: SHA256 (32 bytes). Never mix them.
- If the program is not 20 or 32 bytes, use witness version >= 1.
- Verify hash byte length in a unit test before integrating.
When it happens
Trigger: encode('bc', [0, ...15bytes], 'Bech32', true), encode('bc', [0, ...21bytes], 'Bech32', true), encode('bc', [0, ...33bytes], 'Bech32', true). Triggered after the general 2-40 length check passes but the v0-specific check fails.
Common situations: Using a v0 program with the wrong hash length (e.g. SHA256 of a script for what was meant to be P2WPKH); truncating a 20-byte hash to 19; appending a checksum or version byte to the program; mismatch between intended address type (PKH vs SH) and hash function.
Related errors
- Invalid witness version: ${witnessVersion}. Must be 0-16.
- Invalid witness program length: ${witnessProgram.length}. Mu
- Invalid padding: too many bits remaining
- Encoded string exceeds maximum length of 90 characters (got
- Invalid Bech32 string: exceeds maximum length of 90 characte
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/5ab8228ed2162446.
Report an issue: GitHub.