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

  1. Implement Writable (write/readFields) on the class — the most common fix — and keep declaring it as itself.
  2. Convert to a protobuf Message if the pipeline is protobuf-oriented.
  3. 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.
  4. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/092a685e2fe873de. Report an issue: GitHub.