apache/beam · error · IllegalStateException

error when invoking Coder factory method

Error message

error when invoking Coder factory method 

What it means

When a CoderProvider built by CoderProviders.fromStaticMethods is asked for a coder, it reflectively invokes the Coder class's static `of` factory method. If that invocation fails for any reflective reason (inaccessible, wrong arguments, the factory itself threw, class static-initializer failure, or a null result), coderFor wraps it in this IllegalStateException. It indicates the Coder class's factory method is broken or incompatible with the component coders supplied at runtime, not a problem with the pipeline code calling coderFor.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/coders/CoderProviders.java:79

    @Override
    public <T> Coder<T> coderFor(TypeDescriptor<T> type, List<? extends Coder<?>> componentCoders)
        throws CannotProvideCoderException {
      if (!this.rawType.equals(type.getRawType())) {
        throw new CannotProvideCoderException(
            String.format(
                "Unable to provide coder for %s, this factory can only provide coders for %s",
                type, this.rawType));
      }
      try {
        return (Coder<T>)
            Preconditions.checkStateNotNull(
                factoryMethod.invoke(this.rawType /* ignored */, componentCoders.toArray()));
      } catch (IllegalAccessException
          | IllegalArgumentException
          | InvocationTargetException
          | NullPointerException
          | ExceptionInInitializerError exn) {
        throw new IllegalStateException(
            "error when invoking Coder factory method " + factoryMethod, exn);
      }
    }

    ////////////////////////////////////////////////////////////////////////////////

    // Type raw type used to filter the incoming type on.
    private final Class<?> rawType;

    // Method to create a coder given component coders
    // For a Coder class of kind * -> * -> ... n times ... -> *
    // this has type Coder<?> -> Coder<?> -> ... n times ... -> Coder<T>
    private final Method factoryMethod;

    /** Returns a CoderProvider that invokes the given static factory method to create the Coder. */
    private CoderProviderFromStaticMethods(Class<?> rawType, Class<?> coderClazz) {
      this.rawType = rawType;
      this.factoryMethod = getFactoryMethod(coderClazz);

View on GitHub (pinned to 12126d8942)

Solutions

  1. Read the cause (exn) in the stack trace — it is the real failure from the static `of` factory method; fix the exception thrown inside your Coder's `of` method
  2. Verify the `of` method returns a non-null Coder for all valid component-coder combinations
  3. Check that the number and types of component coders your pipeline supplies match the type parameters of the registered Coder class
  4. If the cause is ExceptionInInitializerError, fix the Coder class's static initializer (missing dependency, bad config)
  5. If the Coder cannot support arbitrary component coders, register it with CoderProviders.forCoder for a concrete TypeDescriptor instead of fromStaticMethods

Example fix

// before: custom coder factory throws on unexpected component coder
public static MyCoder of(Coder<String> c) {
  if (!c.getClass().equals(StringUtf8Coder.class)) { throw new IllegalArgumentException(...); }
  ...
}
// after: handle any Coder<String> or throw CannotProvideCoderException path instead
public static MyCoder of(Coder<String> c) {
  return new MyCoder(c); // accept any Coder<String>
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the factory works before registering
Method of = coderClazz.getDeclaredMethod("of",
    java.util.Arrays.stream(coderClazz.getTypeParameters())
        .map(p -> Coder.class).toArray(Class[]::new));
of.setAccessible(true);
// smoke-test with placeholder coders where feasible; of.getReturnType() must be non-void

Type guard

static boolean hasWorkingFactory(Class<?> coderClazz) {
  try {
    Class<?>[] args = new Class<?>[coderClazz.getTypeParameters().length];
    java.util.Arrays.fill(args, Coder.class);
    Method of = coderClazz.getDeclaredMethod("of", args);
    return Modifier.isStatic(of.getModifiers())
        && coderClazz.isAssignableFrom(of.getReturnType()) && of.isAccessible();
  } catch (ReflectiveOperationException | SecurityException e) { return false; }
}

Try / catch

try {
  Coder<T> coder = registry.getCoder(type, componentCoders);
} catch (IllegalStateException e) {
  // inspect e.getCause() — the failure inside the Coder's static of() method
  logger.error("Coder factory failed for " + type, e.getCause());
  throw new CannotProvideCoderException("factory failure for " + type, e);
}

Prevention

When it happens

Trigger: Calling CoderProviders.fromStaticMethods(rawType, coderClazz) and then resolving a type through CoderRegistry when the registered Coder's static of(Coder<?>...) method throws an exception internally, returns null, or the component coders passed do not match what the factory expects (e.g. wrong arity or incompatible Coder<T> generic binding due to type erasure).

Common situations: A custom Coder's `of` method validates component coders and throws IllegalArgumentException (caught as InvocationTargetException); a Coder was refactored so its `of` no longer accepts the registered component coders; a static initializer of the Coder class fails (ExceptionInInitializerError) from bad config or missing classes; a user-written `of` returns null on an unexpected input.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/f27db77f470bbed5. Report an issue: GitHub.