{"record":{"id":"d75a5ae077e13283","repo":"FiloSottile/age","slug":"illegal-zero-padding","errorCode":null,"errorMessage":"illegal zero padding","messagePattern":"illegal zero padding","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/bech32/bech32.go","lineNumber":100,"sourceCode":"\tbits := byte(0)\n\tmaxv := byte(1<<tobits - 1)\n\tfor idx, value := range data {\n\t\tif value>>frombits != 0 {\n\t\t\treturn nil, fmt.Errorf(\"invalid data range: data[%d]=%d (frombits=%d)\", idx, value, frombits)\n\t\t}\n\t\tacc = acc<<frombits | uint32(value)\n\t\tbits += frombits\n\t\tfor bits >= tobits {\n\t\t\tbits -= tobits\n\t\t\tret = append(ret, byte(acc>>bits)&maxv)\n\t\t}\n\t}\n\tif pad {\n\t\tif bits > 0 {\n\t\t\tret = append(ret, byte(acc<<(tobits-bits))&maxv)\n\t\t}\n\t} else if bits >= frombits {\n\t\treturn nil, fmt.Errorf(\"illegal zero padding\")\n\t} else if byte(acc<<(tobits-bits))&maxv != 0 {\n\t\treturn nil, fmt.Errorf(\"non-zero padding\")\n\t}\n\treturn ret, nil\n}\n\n// Encode encodes the HRP and a bytes slice to Bech32. If the HRP is uppercase,\n// the output will be uppercase.\nfunc Encode(hrp string, data []byte) (string, error) {\n\tvalues, err := convertBits(data, 8, 5, true)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(hrp) < 1 {\n\t\treturn \"\", fmt.Errorf(\"invalid HRP: %q\", hrp)\n\t}\n\tfor p, c := range hrp {\n\t\tif c < 33 || c > 126 {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/internal/bech32/bech32.go#L82-L118","documentation":"convertBits regroups data between bit widths and requires leftover bits to form valid padding. When pad=false (used on decode, 5→8 conversion), if more than tobits-frombits leftover bits remain (bits >= frombits), the padding itself would carry data bits, which is illegal in bech32. The error signals the decoded data part does not represent a whole number of bytes.","triggerScenarios":"Calling bech32.Decode on a string whose data payload length in 5-bit groups is not compatible with whole 8-bit bytes — i.e. len(data)*5 mod 8 leaves >= 5 bits of padding — typically a hand-modified or maliciously crafted bech32 string, or one encoded by a non-conforming encoder.","commonSituations":"Manually edited bech32 strings (e.g. truncated or extended data part); strings produced by other tools that pad incorrectly; corrupted age identity/recipient strings that still pass the bech32 checksum but have invalid padding.","solutions":["Treat the input string as invalid bech32 data; do not attempt to repair it — re-obtain the original string from its source","Verify the string was generated by a conformant bech32 encoder (age's Encode pads correctly); re-encode from the raw key material if you have it","Check the string was not truncated or extended during copy/paste — compare length with the expected format for age identities/recipients"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func isCanonicalBech32Payload(nGroups int) bool {\n\t// 5-bit groups must convert to whole 8-bit bytes with < 5 bits of padding\n\treturn (nGroups*5)%8 < 5\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat any decode padding error as evidence of tampering or corruption; never repair by hand","Only exchange bech32 strings produced by conformant encoders (age itself)","Protect age key strings from manual editing; store and transfer them verbatim","Validate string length against expected format before parsing"],"tags":["bech32","decoding","padding","internal"],"backgroundTag":"bech32-invalid-padding","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}