{"record":{"id":"9bc4984f35ff6f84","repo":"google/guava","slug":"annotation-requires-to-be-s-features-that-earlier","errorCode":null,"errorMessage":"Annotation requires to be %s features that earlier annotations required to be %s.","messagePattern":"Annotation requires to be (.+?) features that earlier annotations required to be (.+?)\\.","errorType":"exception","errorClass":"ConflictingRequirementsException","httpStatus":null,"severity":"error","filePath":"android/guava-testlib/src/com/google/common/collect/testing/features/FeatureUtil.java","lineNumber":289,"sourceCode":"    Set<Feature<?>> morePresentFeatures = moreRequirements.getPresentFeatures();\n    Set<Feature<?>> moreAbsentFeatures = moreRequirements.getAbsentFeatures();\n    checkConflict(\"absent\", absentFeatures, \"present\", morePresentFeatures, source);\n    checkConflict(\"present\", presentFeatures, \"absent\", moreAbsentFeatures, source);\n    presentFeatures.addAll(morePresentFeatures);\n    absentFeatures.addAll(moreAbsentFeatures);\n    return requirements;\n  }\n\n  // Used by incorporateRequirements() only\n  private static void checkConflict(\n      String earlierRequirement,\n      Set<Feature<?>> earlierFeatures,\n      String newRequirement,\n      Set<Feature<?>> newFeatures,\n      Object source)\n      throws ConflictingRequirementsException {\n    if (!disjoint(newFeatures, earlierFeatures)) {\n      throw new ConflictingRequirementsException(\n          String.format(\n              Locale.ROOT,\n              \"Annotation requires to be %s features that earlier \"\n                  + \"annotations required to be %s.\",\n              newRequirement,\n              earlierRequirement),\n          intersection(newFeatures, earlierFeatures),\n          source);\n    }\n  }\n\n  /**\n   * Construct a new {@link java.util.Set} that is the intersection of the given sets.\n   *\n   * @deprecated Use {@link com.google.common.collect.Sets#intersection(Set, Set)} instead.\n   */\n  @Deprecated\n  public static <T> Set<T> intersection(Set<? extends T> set1, Set<? extends T> set2) {","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/google/guava/blob/94f39958baf7ad51ddf9c70e406ed6b188194daa/android/guava-testlib/src/com/google/common/collect/testing/features/FeatureUtil.java#L271-L307","documentation":"Thrown as ConflictingRequirementsException by FeatureUtil.checkConflict when requirements accumulated from earlier annotations (class-level, then method-level) conflict with a new annotation. Unlike error 7 (intra-annotation), this fires during cross-annotation merging in incorporateRequirements: a later annotation demands a feature be present while an earlier one demanded it absent (or vice-versa).","triggerScenarios":"A class-level @CollectionFeature.Require that lists a feature in value(), combined with a method-level annotation (or another class annotation) that lists the same/overlapping feature in absent(); the merge in incorporateRequirements detects the overlap.","commonSituations":"Class-level @Feature.Require declaring broad support and a specific tester method overriding with absent for an overlapping feature; stacking multiple @Require-style annotations whose sets overlap after implication; refactoring a tester and forgetting a class-level annotation.","solutions":["Read the formatted message (newRequirement vs earlierRequirement) and getConflicts() to identify the two annotations and the overlapping feature(s).","Reconcile the class-level and method-level annotations so no feature is required present by one and absent by another.","If you need a tester to opt out of a class-level feature, suppress that tester method instead of declaring it absent at method level while present at class level."],"exampleFix":"// before\n@CollectionFeature.Require(value = CollectionFeature.GENERAL_PURPOSE)\nclass MyListTester extends AbstractListTester {\n  @CollectionFeature.Require(absent = CollectionFeature.SUPPORTS_REMOVE)\n  public void testRemove() { ... } // GENERAL_PURPOSE implies SUPPORTS_REMOVE\n}\n\n// after\n@CollectionFeature.Require(CollectionFeature.GENERAL_PURPOSE)\nclass MyListTester extends AbstractListTester {\n  public void testRemove() { ... } // no conflicting method-level absence\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  // run suite / build requirements\n} catch (ConflictingRequirementsException e) {\n  // e.getConflicts() -> conflicting features; e.getSource() -> offending annotation\n  throw new IllegalStateException(\"Feature conflict in testers: \" + e.getConflicts()\n      + \" from \" + e.getSource(), e);\n}","preventionTips":["Keep class-level and method-level @Require annotations consistent; do not require-present at class level and require-absent at method level for overlapping features.","Use .suppress(Method) to opt a tester out instead of declaring contradictory requirements."],"tags":["guava-testlib","annotations","features","conflicting-requirements"],"backgroundTag":null,"analyzedSha":"94f39958baf7ad51ddf9c70e406ed6b188194daa","analyzedAt":"2026-08-13T22:50:30.265Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}