apache/beam · error · IllegalArgumentException
Property [ ] is marked with contradictory annotations…
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.
Solutions
- Find the property named in the message and inspect all getters/setters for it across the interface hierarchy (including inherited interfaces).
- Remove or unify the contradictory annotations so each property carries exactly one consistent set.
- If both behaviors are needed, split them into two separate properties instead of one.
- 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
- Keep each property's annotations on exactly one declaration in the hierarchy
- Prefer inheriting getters instead of re-declaring them in sub-interfaces
- Validate all options interfaces in a unit test at build time
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
- Expected getter for property
- Property getters are inconsistently marked with @
- All inherited interfaces of
- Class ' ' does not implement PipelineRunner. Supported…
- Class missing a property named ' '.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/959f5f8cf4eb7dea.
Report an issue: GitHub.
Appendix: 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)