pentaho/pentaho-kettle · error · KettleException

AvroInput.Error.JsonDecoderError

Error message

AvroInput.Error.JsonDecoderError

What it means

When the Avro Input step is configured to decode Avro from a JSON-encoded incoming field, DecoderFactory.jsonDecoder(schema, fieldValue) threw an IOException. AvroNestedReader wraps this in a KettleException, meaning the field's string content is not valid JSON matching the configured schema.

Solutions

  1. Log/inspect the raw field value for the failing row to confirm it is valid, complete JSON.
  2. Verify the Avro schema configured in the step matches the JSON payload structure.
  3. Check the 'field to decode' index/selection points at the correct incoming column.
  4. If the data is actually binary Avro, switch the step from JSON to binary decoding mode.

Example fix

// before: field contains malformed/partial JSON
String fieldValue = fieldMeta.getString(incoming[m_fieldToDecodeIndex]);
// after: guard upstream
if (fieldValue == null || !fieldValue.trim().startsWith("{")) throw new KettleException("not valid avro-json: " + fieldValue);
Defensive patterns

Strategy: validation

Validate before calling

String json = fieldMeta.getString(row[fieldIndex]);
try { new org.json.JSONTokener(json).nextValue(); } catch (Exception e) {
  throw new IllegalArgumentException("field is not valid JSON");
}

Try / catch

try {
  rows = reader.avroObjectToKettle(row, space);
} catch (KettleException e) {
  if (e.getMessage().contains("JsonDecoderError")) { logRawValue(row[fieldIndex]); routeToErrorStream(row, e); } else throw e;
}

Prevention

When it happens

Trigger: m_jsonEncoded is true and the string read from incoming[m_fieldToDecodeIndex] cannot be decoded as Avro JSON against m_schemaToUse — malformed JSON, wrong encoding, or JSON shape not matching the schema.

Common situations: Upstream sends truncated or escaped JSON; field contains plain text/binary instead of JSON; schema configured in the step differs from what the JSON payload represents (missing required fields, wrong types).

Related errors


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

Appendix: source

Thrown at plugins/avro-format/core/src/main/java/org/pentaho/di/trans/steps/avro/input/AvroNestedReader.java:1489

            // just resize the existing incoming array (if necessary) and return
            // the incoming values
            result[ 0 ] = RowDataUtil.resizeArray( incoming, m_outputRowMeta.size() );
            return result;
          }

          // if necessary, set the current datum reader and top level structure
          // for the incoming schema
          if ( m_schemaInField ) {
            ValueMetaInterface schemaMeta = m_incomingRowMeta.getValueMeta( m_schemaFieldIndex );
            String schemaToUse = schemaMeta.getString( incoming[ m_schemaFieldIndex ] );
            setSchemaToUse( schemaToUse, m_cacheSchemas, space );
          }
          if ( m_jsonEncoded ) {
            try {
              String fieldValue = fieldMeta.getString( incoming[ m_fieldToDecodeIndex ] );
              m_decoder = m_factory.jsonDecoder( m_schemaToUse, fieldValue );
            } catch ( IOException e ) {
              throw new KettleException(
                BaseMessages.getString( PKG,
                  "AvroInput.Error.JsonDecoderError" ) );
            }
          } else {
            byte[] fieldValue = fieldMeta.getBinary( incoming[ m_fieldToDecodeIndex ] );
            m_decoder = m_factory.binaryDecoder( fieldValue, null );
          }
        }

        if ( m_topLevelRecord != null ) {
          // special case for top-level record. In case we actually
          // have a top level union, reassign the record so that
          // we have the correctly populated object in the case
          // where our last record instance can't be reused (i.e.
          // the next record read is a different one from the union
          // than the last one).

          m_topLevelRecord = (GenericData.Record) m_datumReader.read( m_topLevelRecord, m_decoder );

View on GitHub (pinned to f3058517a1)