apache/iceberg · error · IllegalArgumentException

Cannot write unknown type:

Error message

Cannot write unknown type: 

What it means

SchemaParser.toJson(Type, JsonGenerator) serializes a Type by dispatching on its type id (struct, list, map, and primitives). If a type falls through all known cases, it throws this IllegalArgumentException, meaning an unrecognized/unknown Type implementation reached the schema serializer.

Source

Thrown at core/src/main/java/org/apache/iceberg/SchemaParser.java:159

  }

  static void toJson(Type type, JsonGenerator generator) throws IOException {
    if (type.isPrimitiveType() || type.isVariantType()) {
      generator.writeString(type.toString());
    } else {
      Type.NestedType nested = type.asNestedType();
      switch (type.typeId()) {
        case STRUCT:
          toJson(nested.asStructType(), generator);
          break;
        case LIST:
          toJson(nested.asListType(), generator);
          break;
        case MAP:
          toJson(nested.asMapType(), generator);
          break;
        default:
          throw new IllegalArgumentException("Cannot write unknown type: " + type);
      }
    }
  }

  public static void toJson(Schema schema, JsonGenerator generator) throws IOException {
    toJson(schema.asStruct(), schema.schemaId(), schema.identifierFieldIds(), generator);
  }

  public static String toJson(Schema schema) {
    return toJson(schema, false);
  }

  public static String toJson(Schema schema, boolean pretty) {
    return JsonUtil.generate(
        gen -> toJson(schema.asStruct(), schema.schemaId(), schema.identifierFieldIds(), gen),
        pretty);
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use only standard Iceberg Types (Types.StructType, ListType, MapType, primitive types) in the schema
  2. Align Iceberg versions so the writer's types are known to the parser
  3. If a custom type is required, convert it to a supported standard type before serializing

Example fix

// before
Schema schema = new Schema(Arrays.asList(Types.NestedField.optional(1, "f", customType)));
SchemaParser.toJson(schema, generator); // throws
// after
Type compatible = mapCustomToStandardType(customType); // e.g. Types.StringType.get()
Schema schema = new Schema(Arrays.asList(Types.NestedField.optional(1, "f", compatible)));
SchemaParser.toJson(schema, generator);
Defensive patterns

Strategy: validation

Validate before calling

for (Types.NestedField f : schema.columns()) {
  Preconditions.checkArgument(isStandardType(f.type()), "Non-standard type on field %s: %s", f.name(), f.type());
}
static boolean isStandardType(Type t) {
  return t instanceof Types.BooleanType || t instanceof Types.IntegerType || t instanceof Types.LongType || t instanceof Types.FloatType || t instanceof Types.DoubleType || t instanceof Types.DateType || t instanceof Types.TimeType || t instanceof Types.TimestampType || t instanceof Types.StringType || t instanceof Types.UUIDType || t instanceof Types.FixedType || t instanceof Types.BinaryType || t instanceof Types.DecimalType || t instanceof Types.ListType || t instanceof Types.MapType || t instanceof Types.StructType;
}

Type guard

static boolean isSerializableType(Type t) {
  switch (t.typeId()) {
    case STRUCT: case LIST: case MAP: return true;
    case BOOLEAN: case INTEGER: case LONG: case FLOAT: case DOUBLE: case DATE: case TIME:
    case TIMESTAMP: case STRING: case UUID: case FIXED: case BINARY: case DECIMAL: return true;
    default: return false;
  }
}

Try / catch

try {
  SchemaParser.toJson(schema, generator);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Cannot write unknown type")) throw new IllegalStateException("Schema contains a type unknown to SchemaParser: " + e.getMessage(), e);
  throw e;
}

Prevention

When it happens

Trigger: Calling SchemaParser.toJson(schema, generator) (directly or via table metadata serialization) with a schema containing a Type implementation the parser does not handle — typically a custom Type implementation or one from a different Iceberg version.

Common situations: Custom Type subclasses in embedded/forked builds; mixed Iceberg jar versions where a newer type (e.g. a new variant/unknown type) is serialized by an older parser; test doubles of Type that don't implement the standard hierarchy.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/fb04dccac16cb438. Report an issue: GitHub.