pentaho/pentaho-kettle · error · KettleValueException

invalid hex digit ' '.

Error message

invalid hex digit '<c>'.

What it means

ValueDataUtil.chopHexToBytes converts a hex string to a byte array and validates every hex nibble character. When a character is outside 0-9, A-F, a-f it throws this KettleValueException naming the offending character, because the input is not a valid hex string (e.g. odd characters, whitespace, or odd-length garbage).

Solutions

  1. Inspect the reported character in the message and clean the input string: strip '0x' prefix, spaces, colons, dashes
  2. Validate the string with a regex ^[0-9A-Fa-f]+$ before calling chopHexToBytes
  3. Ensure the string length is even; pad with a leading '0' if odd
  4. Fix the upstream producer so it emits pure hex digits

Example fix

// before
byte[] bytes = ValueDataUtil.chopHexToBytes( hexInput ); // "0x deadBEEF;"
// after
String clean = hexInput == null ? "" : hexInput.replaceAll( "[^0-9A-Fa-f]", "" );
if ( clean.length() % 2 == 1 ) clean = "0" + clean;
byte[] bytes = ValueDataUtil.chopHexToBytes( clean );
Defensive patterns

Strategy: validation

Validate before calling

if ( hex == null || !hex.matches( "[0-9A-Fa-f]+" ) || hex.length() % 2 != 0 ) throw new IllegalArgumentException( "Invalid hex: " + hex );

Type guard

boolean isHexString( String s ) { return s != null && s.matches( "[0-9A-Fa-f]+" ) && s.length() % 2 == 0; }

Try / catch

try {
  return ValueDataUtil.chopHexToBytes( hex );
} catch ( KettleValueException e ) {
  log.warn( "Bad hex input '" + hex + "' -> " + e.getMessage() );
  return hex.replaceAll( "[^0-9A-Fa-f]", "" ).getBytes(); // fallback cleaning
}

Prevention

When it happens

Trigger: Calling ValueDataUtil.chopHexToBytes(hexString) (used by the HEX string decode path in transformations) where the string contains any character outside [0-9A-Fa-f], such as '0x' prefix, spaces, '-', 'g'-'z', or an embedded separator.

Common situations: Decoding a hex value that was copy-pasted with a '0x' prefix or colons/spaces (MAC-address style); a binary column exported with different encoding; uppercase/lowercase confusion is fine, but chars like 'O' vs '0' from OCR/manual entry fail.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/36a081e2603117f1. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/row/ValueDataUtil.java:1841

    // we assume a leading 0 if the length is not even.
    if ( ( len % 2 ) == 1 ) {
      evenByte = false;
    }

    int nibble;
    int i, j;
    for ( i = 0, j = 0; i < len; i++ ) {
      char c = hexString.charAt( i );

      if ( ( c >= '0' ) && ( c <= '9' ) ) {
        nibble = c - '0';
      } else if ( ( c >= 'A' ) && ( c <= 'F' ) ) {
        nibble = c - 'A' + 0x0A;
      } else if ( ( c >= 'a' ) && ( c <= 'f' ) ) {
        nibble = c - 'a' + 0x0A;
      } else {
        throw new KettleValueException( "invalid hex digit '" + c + "'." );
      }

      if ( evenByte ) {
        nextByte = ( nibble << 4 );
      } else {
        nextByte += nibble;
        chArray[j] = (char) nextByte;
        j++;
      }

      evenByte = !evenByte;
    }
    return new String( chArray );
  }

  /**
   * Change a string into its hexadecimal representation. E.g. if Value contains string "a" afterwards it would contain
   * value "0061".

View on GitHub (pinned to f3058517a1)