apache/beam · error · IllegalArgumentException

Property [%s] is marked with contradictory annotations. Foun

Error message

Property [%s] is marked with contradictory annotations. Found [%s].

What it means

Thrown by PipelineOptionsFactory when a single property getter/setter group on a PipelineOptions interface carries two different property annotations (e.g. both @Description annotations conflicting markers such as @Default and @Hidden via distinct annotation predicates) that cannot all apply simultaneously. Beam validates annotation consistency while building the options class and refuses to create an options object with contradictory metadata.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/options/PipelineOptionsFactory.java:1141

      final AnnotationPredicates annotationPredicates) {
    List<InconsistentlyAnnotatedGetters> inconsistentlyAnnotatedGetters = new ArrayList<>();
    for (final PropertyDescriptor descriptor : descriptors) {
      if (descriptor.getReadMethod() == null
          || IGNORED_METHODS.contains(descriptor.getReadMethod())) {
        continue;
      }

      SortedSet<Method> getters = methodNameToAllMethodMap.get(descriptor.getReadMethod());
      SortedSet<Method> gettersWithTheAnnotation =
          Sets.filter(getters, annotationPredicates.forMethod);
      Set<Annotation> distinctAnnotations =
          gettersWithTheAnnotation.stream()
              .flatMap(method -> Arrays.stream(method.getAnnotations()))
              .filter(annotationPredicates.forAnnotation)
              .collect(Collectors.toSet());

      if (distinctAnnotations.size() > 1) {
        throw new IllegalArgumentException(
            String.format(
                "Property [%s] is marked with contradictory annotations. Found [%s].",
                descriptor.getName(),
                gettersWithTheAnnotation.stream()
                    .flatMap(
                        method ->
                            Arrays.stream(method.getAnnotations())
                                .filter(annotationPredicates.forAnnotation)
                                .map(
                                    annotation ->
                                        String.format(
                                            "[%s on %s]",
                                            ReflectHelpers.formatAnnotation(annotation),
                                            ReflectHelpers.formatMethodWithClass(method))))
                    .collect(Collectors.joining(", "))));
      }

      Iterable<String> getterClassNames =

View on GitHub (pinned to 12126d8942)

Solutions

  1. Find the property named in the message and inspect all getters/setters for it across the interface hierarchy (including inherited interfaces).
  2. Remove or unify the contradictory annotations so each property carries exactly one consistent set.
  3. If both behaviors are needed, split them into two separate properties instead of one.
  4. Rebuild and rerun; the factory caches validation so re-run fromArgs/create after the fix.

Example fix

// before
interface MyOptions extends PipelineOptions {
  @Default.String("a")
  String getFoo();
}
interface OtherOptions extends PipelineOptions {
  @Hidden
  String getFoo();
}
// after
interface MyOptions extends PipelineOptions {
  @Default.String("a")
  String getFoo();
}
Defensive patterns

Strategy: validation

Validate before calling

for (java.lang.reflect.Method m : MyOptions.class.getMethods()) {
  java.util.Set<Class<?>> anns = new java.util.HashSet<>();
  for (java.lang.annotation.Annotation a : m.getAnnotations()) anns.add(a.annotationType());
  if (m.getName().startsWith("get") && anns.size() > 1) {
    throw new IllegalStateException("Property " + m.getName() + " has multiple property annotations: " + anns);
  }
}

Try / catch

try {
  PipelineOptions options = PipelineOptionsFactory.fromArgs(args).as(MyOptions.class);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("contradictory annotations")) { /* fix interface annotations */ }
  throw e;
}

Prevention

When it happens

Trigger: Calling PipelineOptionsFactory.fromArgs(...).as(SomeOptions.class) (or .create()) where the distinctAnnotations set built from all getters of one property has size > 1, i.e. the same property is marked with mutually exclusive annotations across the interface hierarchy.

Common situations: A property getter is annotated in one sub-interface and re-annotated differently in another sub-interface that both feed the final options interface; copy-pasting a getter and editing its annotations while leaving both methods registered; merging option interfaces during a refactor.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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