google/guava · error · AssertionError

Serialization failed on return value of %s

Error message

Serialization failed on return value of %s

What it means

Thrown by FactoryMethodReturnValueTester.testSerializable() when reserialize(instance) throws for an object returned by a static factory. The returned object is not serializable (missing Serializable, non-serializable field, or write/readObject mismatch). The cause is unwrapped via getCause() and wrapped with the factory name.

Source

Thrown at android/guava-testlib/src/com/google/common/testing/ClassSanityTester.java:514

    /**
     * Runs serialization test on the return values of the static methods.
     *
     * <p>Test fails if default value cannot be determined for a constructor or factory method
     * parameter, or if the constructor or factory method throws exception.
     *
     * @return this tester
     */
    @CanIgnoreReturnValue
    @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
    public FactoryMethodReturnValueTester testSerializable() throws Exception {
      for (Invokable<?, ?> factory : getFactoriesToTest()) {
        Object instance = instantiate(factory);
        if (instance != null) {
          try {
            reserialize(instance);
          } catch (Exception e) { // sneaky checked exception
            throw new AssertionError(
                "Serialization failed on return value of " + factory, e.getCause());
          }
        }
      }
      return this;
    }

    /**
     * Runs equals and serialization test on the return values.
     *
     * <p>Test fails if default value cannot be determined for a constructor or factory method
     * parameter, or if the constructor or factory method throws exception.
     *
     * @return this tester
     */
    @CanIgnoreReturnValue
    @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
    public FactoryMethodReturnValueTester testEqualsAndSerializable() throws Exception {

View on GitHub (pinned to 94f39958ba)

Solutions

  1. Read the wrapped cause to find the offending field/class.
  2. Make the declaring class implement java.io.Serializable and mark non-serializable fields transient (with custom readResolve/writeReplace if needed).
  3. If the class is intentionally non-serializable, exclude it from the testSerializable() pass rather than letting it fail.

Example fix

// before
public final class Token { private final DataSource ds; ... }

// after
public final class Token implements Serializable {
  private final String id;
  private transient DataSource ds; // not serialized
  private Object readResolve() { ds = lookupDataSource(); return this; }
}
Defensive patterns

Strategy: validation

Validate before calling

Object instance = factory.invoke(null); // static factory
if (instance != null && !(instance instanceof java.io.Serializable))
  throw new IllegalStateException(factory + " returns non-Serializable instance");

Type guard

static boolean isSerializableReturn(java.lang.reflect.Method m) {
  return java.io.Serializable.class.isAssignableFrom(m.getReturnType());
}

Prevention

When it happens

Trigger: Calling ClassSanityTester.testSerializable() (or testAll()) on a class whose static factory returns a non-Serializable instance, or an instance whose transient graph fails to round-trip.

Common situations: A class meant to be serializable but missing implements Serializable; fields holding non-serializable collaborators (lambdas, anonymous classes, JDBC connections); custom writeObject/readObject that are not symmetric.

Related errors


AI-assisted analysis of google/guava@94f39958ba (2026-08-13). Data as JSON: /api/errors/136f7e08e89587cc. Report an issue: GitHub.