{"record":{"id":"c47a7c9b1fb04f48","repo":"in3rsha/sha256-animation","slug":"invalid-input-to-hash256-rb-expecting-even-number","errorCode":null,"errorMessage":"Invalid input to hash256.rb. Expecting even number of hex characters (i.e. bytes).","messagePattern":"Invalid input to hash256\\.rb\\. Expecting even number of hex characters \\(i\\.e\\. bytes\\)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hash256.rb","lineNumber":18,"sourceCode":"require_relative \"sha256lib.rb\"\n\n# ----------\n# hash256.rb - The hash function used in Bitcoin. Basically just runs sha256.rb twice.\n# ----------\n\n# Command Line Arguments\n$input = ARGV[0] || \"0x0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c\"    # \"string\"|\"0xaabbcc\"|\"0b10110100\"\n$delay = ARGV[1] || \"fast\" # [enter|normal|fast|nodelay]\n\n# Assume that every input is hexadecimal bytes\nif $input[0..1] != \"0x\"\n  $input = \"0x\" + $input # prepend 0x if there isn't one (so the upcoming functions can detect it correctly)\nend\n\n# Make sure it's a valid size (even number of characters)\nif $input.size % 2 != 0\n  puts \"Invalid input to hash256.rb. Expecting even number of hex characters (i.e. bytes).\"\n  exit\nend\n\n# Convert hex to bytes\n$type = input_type($input)\n$bytes = bytes($input, $type)\n$message = $bytes.map { |x| x.to_s(2).rjust(8, \"0\") }.join\n\n# Note about hitting enter to step\nif $delay == \"enter\"\n  puts \"Hit enter to step through.\"\n  STDIN.gets\nend\n\n# Catch Ctrl-C to prevent unsightly errors when terminating early\nSignal.trap(\"SIGINT\") do\n  exit\nend","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/in3rsha/sha256-animation/blob/871e976d69e66474ef5239ee82031b7d87cbcafc/hash256.rb#L1-L36","documentation":"hash256.rb is the Bitcoin double-SHA-256 runner built on sha256lib.rb; it insists input be whole bytes written in hex. It first prepends 0x to any argument lacking it, then requires the total string size to be even — since the prefix is 2 characters, this is exactly the rule that the hex digit count is even (2 digits per byte). An odd digit count would leave half a byte, so the script prints this message and exits before any hashing starts.","triggerScenarios":"ruby hash256.rb 0xabc (3 hex digits, total size 5, odd); ruby hash256.rb abc (0x gets prepended first, then 0xabc fails the same way); any 80-byte Bitcoin block header where a paste dropped exactly one of its 160 hex characters; a value like 0x05 trimmed down to 0x5.","commonSituations":"Hand-copying a block-header hex string and losing one character; building headers by concatenating fields (version, previous block, merkle root, time, bits, nonce) where one field was not zero-padded to an even digit count; shell variables carrying a trailing newline that flips the parity of the character count.","solutions":["Pad with a leading zero until the hex digit count is even — every byte is exactly 2 digits (0xabc becomes 0x0abc)","Recount a pasted block header: 80 bytes means 160 hex digits; an odd count means a dropped or added character","Format every concatenated field with %02x (or rjust(2, '0')) so no field ever contributes an odd digit","Pre-validate in the caller: input.delete_prefix('0x').size.even? before invoking hash256.rb"],"exampleFix":"# before\nruby hash256.rb 0xabc    # -> Invalid input to hash256.rb. Expecting even number of hex characters (i.e. bytes).\n\n# after\nruby hash256.rb 0x0abc   # 2 whole bytes, hashes fine","handlingStrategy":"validation","validationCode":"hex = input.to_s.chomp.delete_prefix('0x')\nraise ArgumentError, 'hex digit count must be even (whole bytes), got ' + hex.size.to_s unless hex.size.even?\nsystem('ruby', 'hash256.rb', '0x' + hex)","typeGuard":"def whole_byte_hex?(s)\n  digits = s.to_s.chomp.delete_prefix('0x')\n  digits.match(/[^0-9a-fA-F]/).nil? && digits.size.even?\nend","tryCatchPattern":"begin\n  ARGV.replace([hex_arg, 'fast'])\n  load 'hash256.rb' # prints the message, then exits\nrescue SystemExit\n  warn 'hash256.rb rejected the input (odd number of hex digits)'\nend","preventionTips":["Format every hex byte as exactly 2 digits with %02x when assembling inputs","Sanity-check known lengths: a Bitcoin block header is 80 bytes = 160 hex digits","Check digit-count parity in the caller before spawning hash256.rb","chomp pasted and shell-provided strings — a trailing newline changes the parity the size check sees"],"tags":["ruby","bitcoin","hash256","hex","input-validation"],"backgroundTag":"odd-length-hex-string","analyzedSha":"871e976d69e66474ef5239ee82031b7d87cbcafc","analyzedAt":"2026-08-23T12:17:23.862Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}