apache/hadoop · error · IOException
Can't write: {instance} as {declaredClass}
Error message
Can't write: {instance} as {declaredClass} What it means
Thrown by ObjectWritable.writeObject when the instance's declared class is a reference type that none of the supported branches handle: not a String, enum, Writable, protobuf Message, array, or NullInstance. ObjectWritable is a closed serialization framework — it cannot magically serialize arbitrary Java objects, so an unsupported POJO falls through to this IOException naming the instance and declared class.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/ObjectWritable.java:232
} else if (declaredClass == Float.TYPE) { // float
out.writeFloat(((Float)instance).floatValue());
} else if (declaredClass == Double.TYPE) { // double
out.writeDouble(((Double)instance).doubleValue());
} else if (declaredClass == Void.TYPE) { // void
} else {
throw new IllegalArgumentException("Not a primitive: "+declaredClass);
}
} else if (declaredClass.isEnum()) { // enum
UTF8.writeString(out, ((Enum)instance).name());
} else if (Writable.class.isAssignableFrom(declaredClass)) { // Writable
UTF8.writeString(out, instance.getClass().getName());
((Writable)instance).write(out);
} else if (Message.class.isAssignableFrom(declaredClass)) {
((Message)instance).writeDelimitedTo(
DataOutputOutputStream.constructOutputStream(out));
} else {
throw new IOException("Can't write: "+instance+" as "+declaredClass);
}
}
/**
* Read a {@link Writable}, {@link String}, primitive type, or an array of
* the preceding.
*
* @param conf configuration.
* @param in DataInput.
* @return Object.
* @throws IOException raised on errors performing I/O.
*/
public static Object readObject(DataInput in, Configuration conf)
throws IOException {
return readObject(in, null, conf);
}
View on GitHub (pinned to 2add963021)
Solutions
- Implement Writable (write/readFields) on the class — the most common fix — and keep declaring it as itself.
- Convert to a protobuf Message if the pipeline is protobuf-oriented.
- If the class cannot be modified, wrap it: store a serialized form (e.g. JSON/bytes in a Text or BytesWritable) instead of the raw object.
- For simple values, use String or a boxed primitive representation.
Example fix
// before: plain POJO — ObjectWritable cannot serialize it
class Point { int x, y; }
ObjectWritable.writeObject(out, new Point(), Point.class, conf); // throws
// after: make the class Writable
class Point implements Writable {
int x, y;
public void write(DataOutput out) throws IOException { out.writeInt(x); out.writeInt(y); }
public void readFields(DataInput in) throws IOException { x = in.readInt(); y = in.readInt(); }
}
ObjectWritable.writeObject(out, new Point(), Point.class, conf); Defensive patterns
Strategy: type-guard
Validate before calling
if (!(instance instanceof Writable)
&& !(instance instanceof String)
&& !(instance instanceof Enum)
&& !(instance instanceof com.google.protobuf.Message)
&& !instance.getClass().isArray()) {
throw new IllegalArgumentException(
"Type " + instance.getClass() + " is not serializable by ObjectWritable");
}
ObjectWritable.writeObject(out, instance, declaredClass, conf); Type guard
static boolean isObjectWritableSerializable(Object o) {
return o == null
|| o instanceof Writable
|| o instanceof String
|| o instanceof Enum
|| o instanceof com.google.protobuf.Message
|| o.getClass().isArray();
} Try / catch
try {
ObjectWritable.writeObject(out, instance, declaredClass, conf);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Can't write")) {
throw new IllegalStateException("Class " + instance.getClass()
+ " must implement Writable (or be String/enum/protobuf Message) "
+ "to cross ObjectWritable", e);
}
throw e;
} Prevention
- Make every custom type in RPC/data paths implement Writable from day one.
- For third-party classes you can't modify, wrap their state in Text/BytesWritable (e.g. JSON).
- Add a compile-time convention check or ArchUnit rule: no type enters ObjectWritable unless Writable/enum/String/Message/array.
When it happens
Trigger: writeObject(out, new MyPojo(...), MyPojo.class, conf) where MyPojo implements none of the supported interfaces; putting a custom business object into an RPC method parameter or Writable field serialized via ObjectWritable without making it Writable.
Common situations: Adding a new field/parameter type to an RPC protocol that uses ObjectWritable and forgetting to implement Writable; migrating plain POJOs into Hadoop RPC paths; third-party classes that cannot be modified showing up in serialized data.
Related errors
- Not a primitive: {declaredClass}
- readObject can't find class {className}
- Cannot wrap ${class}
- Exception while get content summary
- f.toString()
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/092a685e2fe873de.
Report an issue: GitHub.