{"record":{"id":"6da3a223189e16d6","repo":"apache/maven","slug":"the-typed-annotation-must-contain-only-interfaces","errorCode":null,"errorMessage":"The Typed annotation must contain only interfaces but the following types are not: ${nonInterfaces}","messagePattern":"The Typed annotation must contain only interfaces but the following types are not: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"impl/maven-impl/src/main/java/org/apache/maven/impl/di/SessionScope.java","lineNumber":136,"sourceCode":"\n    protected Class<?>[] getInterfaces(Class<?> superType) {\n        if (superType.isInterface()) {\n            return new Class<?>[] {superType};\n        }\n        for (Annotation a : superType.getAnnotations()) {\n            Class<? extends Annotation> annotationType = a.annotationType();\n            if (isTypeAnnotation(annotationType)) {\n                try {\n                    Class<?>[] value =\n                            (Class<?>[]) annotationType.getMethod(\"value\").invoke(a);\n                    if (value.length == 0) {\n                        // Only direct interfaces implemented by the class\n                        value = superType.getInterfaces();\n                    }\n                    List<Class<?>> nonInterfaces =\n                            Stream.of(value).filter(c -> !c.isInterface()).toList();\n                    if (!nonInterfaces.isEmpty()) {\n                        throw new IllegalArgumentException(\n                                \"The Typed annotation must contain only interfaces but the following types are not: \"\n                                        + nonInterfaces);\n                    }\n                    return value;\n                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {\n                    throw new IllegalStateException(e);\n                }\n            }\n        }\n        throw new IllegalArgumentException(\n                \"The use of session scoped proxies require a org.apache.maven.api.di.Typed, org.eclipse.sisu.Typed or javax.enterprise.inject.Typed annotation\");\n    }\n\n    protected boolean isTypeAnnotation(Class<? extends Annotation> annotationType) {\n        return \"org.apache.maven.api.di.Typed\".equals(annotationType.getName());\n    }\n\n    /**","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-impl/src/main/java/org/apache/maven/impl/di/SessionScope.java#L118-L154","documentation":"When SessionScope builds a proxy for a session-scoped implementation, it reads the interfaces to proxy from a @Typed annotation's value array. The proxy can only implement interfaces, so any listed type that is a class triggers IllegalArgumentException naming the offending classes. Either annotate with only interface types, or leave value empty so the component's directly-implemented interfaces are used.","triggerScenarios":"Annotating a session-scoped component with @Typed(SomeConcreteClass.class) or @Typed({MyApi.class, MyImpl.class}) where MyImpl is a class; copying a sisu @Typed listing from a non-proxied component onto a session-scoped one.","commonSituations":"Migrating components from Guice/Sisu bindings (where @Typed with classes was tolerated) into session scope; auto-generated annotations listing the implementation class; refactors that added the impl class to the Typed list.","solutions":["Change the @Typed value to list interfaces only, e.g. @Typed(MyService.class) with MyService an interface","Omit the value entirely (@Typed or @Typed({})) so the scope falls back to superType.getInterfaces()","Re-check after refactors that no concrete class crept into the annotation"],"exampleFix":"// before\n@SessionScoped\n@Typed({MyService.class, MyServiceImpl.class})\npublic class MyServiceImpl implements MyService { ... }\n\n// after\n@SessionScoped\n@Typed(MyService.class)\npublic class MyServiceImpl implements MyService { ... }","handlingStrategy":"validation","validationCode":"// verify a @Typed value contains interfaces only, before the container creates the proxy\nTyped typed = MyServiceImpl.class.getAnnotation(Typed.class);\nif (typed != null) {\n    for (Class<?> c : typed.value()) {\n        if (!c.isInterface()) throw new IllegalStateException(\"@Typed lists non-interface: \" + c.getName());\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["List only interfaces in @Typed on session-scoped components","Leave @Typed value empty to auto-use the class's direct interfaces","Add a classpath test asserting @Typed values of all @SessionScoped components are interfaces"],"tags":["maven","di","annotation","proxy","scope"],"backgroundTag":"invalid-annotation-value","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}