apache/iceberg · error · IllegalArgumentException

Cannot write unknown string type:

Error message

Cannot write unknown string type: 

What it means

The same string writer only knows how to encode Avro Utf8 and java.lang.String; any other object type found in the column triggers this IllegalArgumentException including the runtime class name and value. It catches type leakage from upstream data sources.

Source

Thrown at core/src/main/java/org/apache/iceberg/avro/ValueWriters.java:253

  private static class StringWriter implements ValueWriter<Object> {
    private static final StringWriter INSTANCE = new StringWriter();

    private StringWriter() {}

    @Override
    public void write(Object s, Encoder encoder) throws IOException {
      // use getBytes because it may return the backing byte array if available.
      // otherwise, it copies to a new byte array, which is still cheaper than Avro
      // calling toString, which incurs encoding costs
      if (s instanceof Utf8) {
        encoder.writeString((Utf8) s);
      } else if (s instanceof String) {
        encoder.writeString(new Utf8((String) s));
      } else if (s == null) {
        throw new IllegalArgumentException("Cannot write null to required string column");
      } else {
        throw new IllegalArgumentException(
            "Cannot write unknown string type: " + s.getClass().getName() + ": " + s);
      }
    }
  }

  private static class Utf8Writer implements ValueWriter<Utf8> {
    private static final Utf8Writer INSTANCE = new Utf8Writer();

    private Utf8Writer() {}

    @Override
    public void write(Utf8 s, Encoder encoder) throws IOException {
      encoder.writeString(s);
    }
  }

  private static class UUIDWriter implements ValueWriter<UUID> {
    private static final ThreadLocal<ByteBuffer> BUFFER =

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Convert the value to java.lang.String (String.valueOf) before writing
  2. If using Avro GenericData, ensure the column value is Utf8
  3. Check upstream mapping so only String/Utf8 reach the string writer

Example fix

// before
writer.write(stringBuilderValue, encoder);
// after
writer.write(stringBuilderValue.toString(), encoder);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(v instanceof String || v instanceof Utf8)) throw new IllegalArgumentException("string column got " + v.getClass().getName());

Type guard

String asString(Object v) { return v instanceof Utf8 ? ((Utf8) v).toString() : (v instanceof String ? (String) v : v.toString()); }

Try / catch

try { writer.writeValue(encoder, v); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Cannot write unknown string type")) { /* convert to String upstream */ } else throw e; }

Prevention

When it happens

Trigger: Writing CharSequence subclasses (e.g. StringBuilder), or custom string-like types, into a string column; passing objects from another serialization library (e.g. protobuf ByteString) without conversion.

Common situations: Reading with a different engine/row format then writing with the generic writer without conversion; dependency changes returning different CharSequence implementations.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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