{"record":{"id":"257ba807548f512d","repo":"apache/iceberg","slug":"cannot-convert-number-to-variant-unknown-type","errorCode":null,"errorMessage":"Cannot convert Number to variant (unknown type): ${number.getClass().getName()}","messagePattern":"Cannot convert Number to variant \\(unknown type\\): (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordConverter.java","lineNumber":802,"sourceCode":"    if (number instanceof Integer integer) {\n      return Variants.of(integer);\n    }\n    if (number instanceof Long longValue) {\n      return Variants.of(longValue);\n    }\n    if (number instanceof Float floatValue) {\n      return Variants.of(floatValue);\n    }\n    if (number instanceof Double doubleValue) {\n      return Variants.of(doubleValue);\n    }\n    if (number instanceof Byte byteValue) {\n      return Variants.of(byteValue);\n    }\n    if (number instanceof Short shortValue) {\n      return Variants.of(shortValue);\n    }\n    throw new IllegalArgumentException(\n        \"Cannot convert Number to variant (unknown type): \" + number.getClass().getName());\n  }\n\n  @SuppressWarnings(\"JavaUtilDate\")\n  private OffsetDateTime convertOffsetDateTime(Object value) {\n    if (value instanceof Number) {\n      long millis = ((Number) value).longValue();\n      return DateTimeUtil.timestamptzFromMicros(millis * 1000);\n    } else if (value instanceof String) {\n      return parseOffsetDateTime((String) value);\n    } else if (value instanceof OffsetDateTime) {\n      return (OffsetDateTime) value;\n    } else if (value instanceof LocalDateTime) {\n      return ((LocalDateTime) value).atOffset(ZoneOffset.UTC);\n    } else if (value instanceof Date) {\n      return DateTimeUtil.timestamptzFromMicros(((Date) value).getTime() * 1000);\n    }\n    throw new ConnectException(","sourceCodeStart":784,"sourceCodeEnd":820,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordConverter.java#L784-L820","documentation":"The Number-to-Variant conversion in RecordConverter throws this IllegalArgumentException when a Number is neither Byte, Short, Integer, Long, Float, Double, BigDecimal, nor BigInteger — i.e. an unknown Number subtype the converter doesn't map to a Variant primitive.","triggerScenarios":"A custom Number subclass (e.g. AtomicLong, AtomicDouble, Guava/Kotlin numeric types, or a framework-specific numeric wrapper) reaches the Number branch of objectToVariantValue.","commonSituations":"SMTs that emit Atomic* types; deserializers producing exotic numeric wrappers; custom value classes extending Number passed through schemaless records.","solutions":["Convert the value to a standard type (Integer, Long, Double, BigDecimal) before the sink","Normalize exotic Numbers with an SMT (e.g. toLong/toDouble)","Extend RecordConverter and override objectToVariantValue to handle the specific Number subclass","Fix the deserializer to emit standard Java numeric boxed types"],"exampleFix":"// before\nvalue = java.util.concurrent.atomic.AtomicLong(42) // unknown Number type\n// after\nvalue = atomicLong.longValue() // plain Long supported by Variants.of","handlingStrategy":"type-guard","validationCode":"static boolean isStandardNumber(Object v) {\n  return v instanceof Byte || v instanceof Short || v instanceof Integer || v instanceof Long\n      || v instanceof Float || v instanceof Double\n      || v instanceof java.math.BigDecimal || v instanceof java.math.BigInteger;\n}","typeGuard":"static Number toStandardNumber(Number n) {\n  if (isStandardNumber(n)) return n;\n  return java.math.BigDecimal.valueOf(n.doubleValue()); // normalize exotic Number\n}","tryCatchPattern":"try {\n  converter.convertValue(num, Types.VariantType.get());\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Cannot convert Number to variant\")) {\n    log.error(\"Unknown Number subclass: \" + e.getMessage());\n    // retry with ((Number) value).longValue() or new BigDecimal(value.toString())\n  }\n}","preventionTips":["Avoid Atomic*/custom Number subclasses in Connect records","Box to standard types at deserialization time","Normalize exotic numerics in an SMT before the sink","Test deserializers for the exact boxed types they emit"],"tags":["kafka-connect","variant","number","unsupported-type"],"backgroundTag":"type-mismatch","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"}