apache/beam · error · IllegalArgumentException

Wildcard builder not allowed for non-wildcard class.

Error message

Wildcard builder not allowed for non-wildcard class.

What it means

AllowedClass.create rejects an entry using wildcard builder methods ('*') on any class other than the wildcard class '*', because allowing getClass().forName() effectively permits arbitrary code instantiation.

Solutions

  1. Restrict allowedBuilderMethods for specific classes to an explicit list of builder method names.
  2. Reserve allowedBuilderMethods: ['*'] exclusively for the className: '*' entry.
  3. If broad access is truly needed, use a wildcard class entry instead.
  4. Fix generated config templates to never emit '*' builders for named classes.

Example fix

# before
- className: org.example.MyTransform
  allowedBuilderMethods: ['*']
# after
- className: org.example.MyTransform
  allowedBuilderMethods: ['of', 'withX']
Defensive patterns

Strategy: validation

Validate before calling

for (Map<?,?> e : allowedClasses) {
  String cn = (String) e.get("className");
  if (!"*".equals(cn) && "*".equals(e.get("allowedBuilderMethods")))
    throw new IllegalArgumentException("Wildcard builder only allowed for '*'");
}

Type guard

boolean wildcardOk(String className, List<String> builders) { return !"*".equals(builders) || "*".equals(className); }

Try / catch

try { AllowedClass.create(className, builders, ctors); } catch (IllegalArgumentException e) { log.error("Illegal allowlist entry: {}", e.getMessage()); throw new SecurityConfigException(e); }

Prevention

When it happens

Trigger: An allowedClasses entry sets allowedBuilderMethods: ['*'] for a concrete class like 'org.example.Foo'; only the className '*' entry may use wildcard builders.

Common situations: Operators copying wildcard examples but replacing the class name; auto-generated configs propagating wildcards to named classes.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java:605

    public boolean isAllowedConstructorMethod(String methodName) {
      return getAllowedConstructorMethods().contains(methodName)
          || getAllowedConstructorMethods().equals(WILDCARD);
    }

    static AllowedClass create(
        String className,
        List<String> allowedBuilderMethods,
        List<String> allowedConstructorMethods) {
      if (allowedBuilderMethods == null) {
        allowedBuilderMethods = new ArrayList<>();
      }
      if (allowedConstructorMethods == null) {
        allowedConstructorMethods = new ArrayList<>();
      }
      if (allowedBuilderMethods.equals(WILDCARD) && !className.equals("*")) {
        // If we allow getClass().forName(), we allow essentially anything.
        throw new IllegalArgumentException("Wildcard builder not allowed for non-wildcard class.");
      }
      return new AutoValue_JavaClassLookupTransformProvider_AllowedClass(
          className, allowedBuilderMethods, allowedConstructorMethods);
    }
  }

  static Row decodeRow(SchemaApi.Schema schema, ByteString payload) {
    Schema payloadSchema = SchemaTranslation.schemaFromProto(schema);

    if (payloadSchema.getFieldCount() == 0) {
      return Row.withSchema(Schema.of()).build();
    }

    Row row;
    try {
      row = RowCoder.of(payloadSchema).decode(payload.newInput());
    } catch (IOException e) {
      throw new RuntimeException("Error decoding payload", e);

View on GitHub (pinned to 12126d8942)