{"record":{"id":"5535bee8bb3f8dc7","repo":"apache/iceberg","slug":"cannot-extract-value-from-type-recordvalue-getc","errorCode":null,"errorMessage":"Cannot extract value from type: ${recordValue.getClass().getName()}","messagePattern":"Cannot extract value from type: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordUtils.java","lineNumber":58,"sourceCode":"import org.apache.iceberg.relocated.com.google.common.collect.Sets;\nimport org.apache.iceberg.relocated.com.google.common.primitives.Ints;\nimport org.apache.iceberg.types.TypeUtil;\nimport org.apache.iceberg.types.Types.NestedField;\nimport org.apache.iceberg.util.PropertyUtil;\nimport org.apache.kafka.connect.data.Field;\nimport org.apache.kafka.connect.data.Struct;\n\nclass RecordUtils {\n\n  @SuppressWarnings(\"unchecked\")\n  static Object extractFromRecordValue(Object recordValue, String fieldName) {\n    List<String> fields = Splitter.on('.').splitToList(fieldName);\n    if (recordValue instanceof Struct) {\n      return valueFromStruct((Struct) recordValue, fields);\n    } else if (recordValue instanceof Map) {\n      return valueFromMap((Map<String, ?>) recordValue, fields);\n    } else {\n      throw new UnsupportedOperationException(\n          \"Cannot extract value from type: \" + recordValue.getClass().getName());\n    }\n  }\n\n  private static Object valueFromStruct(Struct parent, List<String> fields) {\n    Struct struct = parent;\n    for (int idx = 0; idx < fields.size() - 1; idx++) {\n      Object value = fieldValueFromStruct(struct, fields.get(idx));\n      if (value == null) {\n        return null;\n      }\n      Preconditions.checkState(value instanceof Struct, \"Expected a struct type\");\n      struct = (Struct) value;\n    }\n    return fieldValueFromStruct(struct, fields.get(fields.size() - 1));\n  }\n\n  private static Object fieldValueFromStruct(Struct struct, String fieldName) {","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordUtils.java#L40-L76","documentation":"RecordUtils.extractFromRecordValue only supports Kafka Connect Struct and Map record values when resolving a dotted fieldName (e.g. upsert key columns or partition/route columns). Any other type throws UnsupportedOperationException naming the actual class.","triggerScenarios":"Configuring iceberg.coordinator.key-field / partition-field / route-field (via the sink's field extraction) while the record value is a raw primitive, byte[], or other non-Struct/non-Map Connect type.","commonSituations":"Topics with schema-less or primitive values (string/JSON-as-string) paired with a config expecting nested field lookups; converters producing ByteArray/Json schemas for keys.","solutions":["Ensure the record value schema is a Struct (use JsonConverter with schemas.enable=true or an SMT like HoistField to wrap primitives into a struct).","If values are JSON strings, add a transform that parses JSON into a Struct before the sink.","Change the configured field reference to point at a field that exists in a Struct/Map value.","Use IcebergSinkConfig route/key settings matching the actual record shape."],"exampleFix":"// before: value schema is int64, config expects 'user.id'\n\"iceberg.route-field\": \"user.id\"\n// after: wrap primitive into struct via HoistField then reference\n\"transforms.hoist.type\": \"org.apache.kafka.connect.transforms.HoistField$Value\",\n\"transforms.hoist.field\": \"user\"","handlingStrategy":"type-guard","validationCode":"if (!(record.value() instanceof Struct) && !(record.value() instanceof Map)) {\n  throw new DataException(\"Field extraction requires Struct or Map value\");\n}","typeGuard":"boolean isExtractable(Object v) {\n  return v instanceof Struct || v instanceof Map;\n}","tryCatchPattern":"try { return RecordUtils.extractFromRecordValue(value, fieldName); }\ncatch (UnsupportedOperationException e) { LOG.error(\"non-struct value: {}\", e.getMessage()); throw new RetriableException(e); }","preventionTips":["Use converters that produce Struct values (schemas.enable=true)","Wrap primitives with HoistField before the sink","Validate key/route field paths against the actual value schema"],"tags":["kafka-connect","field-extraction","unsupported-type"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}