{"id":"aae64ee5e85187f6","repo":"junit-team/junit5","slug":"filter-s-must-implement-s-s-or-s","errorCode":null,"errorMessage":"Filter [%s] must implement %s, %s, or %s.","messagePattern":"Filter \\[(.+?)\\] must implement (.+?), (.+?), or (.+?)\\.","errorType":"exception","errorClass":"PreconditionViolationException","httpStatus":null,"severity":"error","filePath":"junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java","lineNumber":369,"sourceCode":"\t@API(status = MAINTAINED, since = \"1.14\")\n\tpublic LauncherDiscoveryRequestBuilder outputDirectoryCreator(OutputDirectoryCreator outputDirectoryCreator) {\n\t\tthis.outputDirectoryCreator = Preconditions.notNull(outputDirectoryCreator,\n\t\t\t\"outputDirectoryCreator must not be null\");\n\t\treturn this;\n\t}\n\n\tprivate void storeFilter(Filter<?> filter) {\n\t\tif (filter instanceof EngineFilter engineFilter) {\n\t\t\tthis.engineFilters.add(engineFilter);\n\t\t}\n\t\telse if (filter instanceof PostDiscoveryFilter postDiscoveryFilter) {\n\t\t\tthis.postDiscoveryFilters.add(postDiscoveryFilter);\n\t\t}\n\t\telse if (filter instanceof DiscoveryFilter<?> discoveryFilter) {\n\t\t\tthis.discoveryFilters.add(discoveryFilter);\n\t\t}\n\t\telse {\n\t\t\tthrow new PreconditionViolationException(\n\t\t\t\t\"Filter [%s] must implement %s, %s, or %s.\".formatted(filter, EngineFilter.class.getSimpleName(),\n\t\t\t\t\tPostDiscoveryFilter.class.getSimpleName(), DiscoveryFilter.class.getSimpleName()));\n\t\t}\n\t}\n\n\t/**\n\t * Builds this discovery request and returns a new builder for creating a\n\t * {@link org.junit.platform.launcher.LauncherExecutionRequest} that is\n\t * initialized to contain the resulting discovery request.\n\t *\n\t * @return a new {@link LauncherExecutionRequestBuilder}\n\t * @since 6.0\n\t */\n\t@API(status = EXPERIMENTAL, since = \"6.0\")\n\tpublic LauncherExecutionRequestBuilder forExecution() {\n\t\treturn LauncherExecutionRequestBuilder.request(build());\n\t}\n","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java#L351-L387","documentation":"Thrown by LauncherDiscoveryRequestBuilder.storeFilter() when a Filter passed to .filters(Filter<?>...) is neither an EngineFilter, a PostDiscoveryFilter, nor a DiscoveryFilter. The builder classifies each filter by instanceof and rejects unknown filter types with PreconditionViolationException naming the offending object and the three accepted interfaces.","triggerScenarios":"Passing a raw Filter implementation, a tag filter wrapped incorrectly, or any custom Filter that does not extend one of the three recognised interfaces into LauncherDiscoveryRequestBuilder.filters(...).","commonSituations":"Passing TagFilter.includeTags(...) correctly is fine (it returns a PostDiscoveryFilter), but passing a hand-rolled Filter or a ClassNameFilter where the static import returns a DiscoveryFilter (which is accepted) vs a plain Filter. Mixing in a org.junit.platform.engine.Filter subtype that is none of the three. Wrong static import returning a generic Filter.","solutions":["Ensure every filter passed implements EngineFilter, PostDiscoveryFilter, or DiscoveryFilter.","Use the documented factory methods (includeEngines, includeTags, includeClassNamePatterns) which return the correct subtypes.","If you have a custom filter, implement PostDiscoveryFilter (most common choice) or DiscoveryFilter."],"exampleFix":"// before\n.filters(new MyRawFilter()) // MyRawFilter only implements Filter<TestDescriptor>\n\n// after\npublic class MyRawFilter implements PostDiscoveryFilter { ... }\n.filters(new MyRawFilter())","handlingStrategy":"type-guard","validationCode":"import org.junit.platform.launcher.EngineFilter;\nimport org.junit.platform.launcher.PostDiscoveryFilter;\nimport org.junit.platform.engine.DiscoveryFilter;\nfor (Filter<?> f : filters) {\n    if (!(f instanceof EngineFilter || f instanceof PostDiscoveryFilter || f instanceof DiscoveryFilter)) {\n        throw new IllegalArgumentException(\"Unsupported filter: \" + f.getClass());\n    }\n}","typeGuard":"static boolean isAcceptableFilter(Filter<?> f) {\n    return f instanceof EngineFilter\n        || f instanceof PostDiscoveryFilter\n        || f instanceof DiscoveryFilter;\n}","tryCatchPattern":null,"preventionTips":["Use the documented factory methods (includeEngines, includeTags, includeClassNamePatterns) which return correct subtypes.","Make custom filters implement PostDiscoveryFilter or DiscoveryFilter.","Unit-test filter wiring against the builder before integration runs."],"tags":["discovery","filter","api-misuse","junit-platform"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}