apache/beam · error · IllegalArgumentException

Config class must be not null!

Error message

Config class must be not null!

What it means

PluginConfigInstantiationUtils.getPluginConfig validates that the PluginConfig subclass passed for reflective instantiation is non-null before walking its field hierarchy. A null configClass would make reflection impossible, so an IllegalArgumentException is thrown immediately.

Solutions

  1. Pass the concrete PluginConfig subclass (e.g., MyPluginConfig.class) instead of null
  2. If the config class comes from generics, capture it explicitly via a TypeToken or pass the Class literal at the call site
  3. Check the builder/factory that supplies configClass for a code path that leaves it unset

Example fix

// before
PluginConfig config = PluginConfigInstantiationUtils.getPluginConfig(params, null);
// after
PluginConfig config = PluginConfigInstantiationUtils.getPluginConfig(params, MyPluginConfig.class);
Defensive patterns

Strategy: type-guard

Validate before calling

if (configClass == null) {
  throw new IllegalArgumentException("configClass must be provided to getPluginConfig");
}

Type guard

static <T extends PluginConfig> boolean validConfigClass(Class<T> c) {
  return c != null && PluginConfig.class.isAssignableFrom(c);
}

Try / catch

try {
  return PluginConfigInstantiationUtils.getPluginConfig(params, configClass);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("Config class must be not null")) { /* resolve config class from generics */ }
  throw e;
}

Prevention

When it happens

Trigger: Calling getPluginConfig(params, null) — typically from a CDAP IO wrapper whose config class was resolved to null, e.g., a generic type parameter that could not be resolved, or a Plugin.of(...) call where the config class argument was null.

Common situations: Passing null because a generic config type was erased or not captured; accidentally passing the plugin class's config field value (null at that point) instead of the class itself; miswiring a builder where the config class is set later than first use.

Related errors


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

Appendix: source

Thrown at sdks/java/io/cdap/src/main/java/org/apache/beam/sdk/io/cdap/PluginConfigInstantiationUtils.java:56

public class PluginConfigInstantiationUtils {

  private static final Logger LOG = LoggerFactory.getLogger(PluginConfigInstantiationUtils.class);
  private static final String MACRO_FIELDS_FIELD_NAME = "macroFields";

  /**
   * Method for instantiating {@link PluginConfig} object of specific class {@code configClass}.
   * After instantiating, it will go over all {@link Field}s with the {@link Name} annotation and
   * set the appropriate parameter values from the {@code params} map for them.
   *
   * @param params map of config fields, where key is the name of the field, value must be String or
   *     boxed primitive
   * @return Config object for given map of arguments and configuration class
   */
  static @Nullable <T extends PluginConfig> T getPluginConfig(
      Map<String, Object> params, Class<T> configClass) {
    // Validate configClass
    if (configClass == null) {
      throw new IllegalArgumentException("Config class must be not null!");
    }
    List<Field> allFields = new ArrayList<>();
    Class<?> currClass = configClass;
    while (currClass != null && !currClass.equals(Object.class)) {
      allFields.addAll(
          Arrays.stream(currClass.getDeclaredFields())
              .filter(f -> !Modifier.isStatic(f.getModifiers()))
              .collect(Collectors.toList()));
      currClass = currClass.getSuperclass();
    }
    InstantiatorFactory instantiatorFactory = new InstantiatorFactory(false);

    @Initialized T config = instantiatorFactory.get(TypeToken.of(configClass)).create();

    if (config != null) {
      for (Field field : allFields) {
        field.setAccessible(true);

View on GitHub (pinned to 12126d8942)