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
- Convert the value to java.lang.String (String.valueOf) before writing
- If using Avro GenericData, ensure the column value is Utf8
- 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
- Normalize CharSequence wrappers with toString() before writing
- Avoid passing protobuf/other-library string types directly
- Add mapping tests for all incoming data types
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
- Reader does not support metadata reading: %s
- Cannot write null to required string column
- Unsupported logical type:
- Unexpected object type for TIMESTAMP logical type. Received:
- Unexpected object type for DATE logical type. Received: ${ob
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d878bfe05ad1582c.
Report an issue: GitHub.