apache/hadoop · critical · RuntimeException

readObject can't find class {className}

Error message

readObject can't find class {className}

What it means

Thrown by ObjectWritable.loadClass(Configuration, String) when the class named in the serialized stream cannot be resolved: Configuration.getClassByName(className) (or Class.forName when conf is null) raises ClassNotFoundException, which is rethrown as this RuntimeException. ObjectWritable stores the concrete class NAME inside the stream for Writable values; on read, that class must exist on the reader's classpath.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/ObjectWritable.java:420

  /**
   * Find and load the class with given name <code>className</code> by first finding
   * it in the specified <code>conf</code>. If the specified <code>conf</code> is null,
   * try load it directly.
   *
   * @param conf configuration.
   * @param className classname.
   * @return Class.
   */
  public static Class<?> loadClass(Configuration conf, String className) {
    Class<?> declaredClass = null;
    try {
      if (conf != null)
        declaredClass = conf.getClassByName(className);
      else
        declaredClass = Class.forName(className);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("readObject can't find class " + className,
          e);
    }
    return declaredClass;
  }

  @Override
  public void setConf(Configuration conf) {
    this.conf = conf;
  }

  @Override
  public Configuration getConf() {
    return this.conf;
  }
  
}

View on GitHub (pinned to 2add963021)

Solutions

  1. Add the jar containing the named class to the reader's classpath (cluster client classpath, job jar lib/, or DistributedCache).
  2. Align Hadoop/dependency versions between writer and reader if the class moved between versions.
  3. If you renamed the class, either keep a serialization-compatible alias or rewrite the data.
  4. Pass a non-null Configuration so class resolution uses the Hadoop classpath (conf.getClassByName) rather than only the system classloader.

Example fix

// before: reading fails, class only on writer's classpath
ObjectWritable ow = new ObjectWritable();
ow.setConf(conf);
ow.readFields(in); // RuntimeException: readObject can't find class com.example.MyValue

// after: ship and register the jar before deserializing
job.addFileToClassPath(new Path("/libs/mytypes-1.0.jar"), fs, conf);
// or on a client: java -cp mytypes-1.0.jar:hadoop-classpath ...
Defensive patterns

Strategy: validation

Validate before calling

try {
  conf.getClassByName(className); // or ObjectWritable.loadClass(conf, className)
} catch (ClassNotFoundException e) {
  throw new IllegalStateException(
      "Class " + className + " from payload missing on this JVM — "
      + "add its jar to the classpath/job jar", e);
}
// safe to readFields now

Type guard

static boolean isClassResolvable(Configuration conf, String className) {
  try {
    ObjectWritable.loadClass(conf, className);
    return true;
  } catch (RuntimeException e) {
    return e.getCause() instanceof ClassNotFoundException ? false : true; // rethrow others
  }
}

Try / catch

try {
  ObjectWritable ow = new ObjectWritable();
  ow.setConf(conf);
  ow.readFields(in);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("readObject can't find class")) {
    failWithClasspathHint(e.getMessage()); // name the missing class and expected jar
  }
  throw e;
}

Prevention

When it happens

Trigger: Deserializing an ObjectWritable/RPC payload whose embedded class name (e.g. com.example.MyWritable) is absent from the reading JVM's classpath; running with conf == null so only Class.forName on the system classloader is used; class renamed/moved between writer and reader versions.

Common situations: Client JVM missing the application jar that defines custom Writable types used in RPC responses; Hadoop/dependency version skew where a class moved packages; shaded/relocated jars changing class names; distributed cache not shipping the job jar to nodes doing the deserialization.

Related errors


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