{"record":{"id":"448f4684705864a4","repo":"gradle/gradle","slug":"cannot-create-a-s-because-this-type-is-not-known","errorCode":null,"errorMessage":"Cannot create a %s because this type is not known to %s. Known types are: %s","messagePattern":"Cannot create a (.+?) because this type is not known to (.+?)\\. Known types are: (.+?)","errorType":"validation","errorClass":"InvalidUserDataException","httpStatus":null,"severity":"error","filePath":"platforms/core-configuration/domain-object-collections/src/main/java/org/gradle/api/internal/DefaultPolymorphicNamedEntityInstantiator.java","lineNumber":47,"sourceCode":"import java.util.Map;\nimport java.util.Set;\n\npublic class DefaultPolymorphicNamedEntityInstantiator<T> implements PolymorphicNamedEntityInstantiator<T> {\n    private final Map<Class<? extends T>, NamedDomainObjectFactory<? extends T>> factories = new HashMap<>();\n    private final Class<? extends T> baseType;\n    private final String displayName;\n\n    public DefaultPolymorphicNamedEntityInstantiator(Class<? extends T> type, String displayName) {\n        this.displayName = displayName;\n        this.baseType = type;\n    }\n\n    @Override\n    public <S extends T> S create(String name, Class<S> type) {\n        @SuppressWarnings(\"unchecked\")\n        NamedDomainObjectFactory<S> factory = (NamedDomainObjectFactory<S>) factories.get(type);\n        if (factory == null) {\n            throw new InvalidUserDataException(\n                    String.format(\"Cannot create a %s because this type is not known to %s. Known types are: %s\", type.getSimpleName(), displayName, getSupportedTypeNames()),\n                    new NoFactoryRegisteredForTypeException());\n        }\n        return factory.create(name);\n    }\n\n    public String getSupportedTypeNames() {\n        List<String> names = new ArrayList<>();\n        for (Class<?> clazz : factories.keySet()) {\n            names.add(clazz.getSimpleName());\n        }\n        Collections.sort(names);\n        return names.isEmpty() ? \"(None)\" : Joiner.on(\", \").join(names);\n    }\n\n    @Override\n    public <U extends T> void registerFactory(Class<U> type, NamedDomainObjectFactory<? extends U> factory) {\n        if (!baseType.isAssignableFrom(type)) {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/core-configuration/domain-object-collections/src/main/java/org/gradle/api/internal/DefaultPolymorphicNamedEntityInstantiator.java#L29-L65","documentation":"Detached resolvers (newDetachedResolver) back adhoc resolution: detached configurations, buildscript/plugin classpath resolution, and settings dependency resolution management. Gradle wires a configureEach guard so that every configuration in that container stays non-consumable, because detached resolvers only represent adhoc root components that never expose variants. Marking any configuration there consumable raises InvalidUserCodeException immediately.","triggerScenarios":"Calling withCanBeConsumed(true)/setCanBeConsumed(true), directly or by copying a consumable configuration's settings, on a configuration living in a detached resolver: a project.configurations.detachedConfiguration(...) instance, plugin-resolution classpath configurations, or settings-level resolution services.","commonSituations":"Generic helper code that 'normalizes' configurations by setting canBeConsumed=true; plugins applying the same configuration template to detached and project containers; copying a consumable configuration into a detached one for adhoc resolution.","solutions":["Do not flip canBeConsumed on detached or plugin-context configurations","Expose variants through a named consumable configuration in the project's own configuration container","Resolve via a resolvable detached configuration and keep it consumption-free"],"exampleFix":"// before\ndef detached = project.configurations.detachedConfiguration(dep)\ndetached.withCanBeConsumed(true) // InvalidUserCodeException\n\n// after\ndef detached = project.configurations.detachedConfiguration(dep)\ndetached.withCanBeResolved(true) // adhoc resolution only, never consumable\n// to expose variants, use the project container instead:\nconfigurations.consumable('myOutgoing') { /* ... */ }","handlingStrategy":"validation","validationCode":"// Guard shared helpers that clone configuration state into detached contexts\ndef template = configurations.findByName('api')\nif (template?.isCanBeConsumable()) {\n    throw new GradleException('Refusing to detach or clone a consumable configuration; detached resolvers are resolve-only')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat detached configurations as resolvable-only","Keep variant exposure (outgoing, extendsFrom of consumables) to named configurations in the project container","Never apply blanket withCanBeConsumed(true) in shared configuration code"],"tags":["gradle","detached-configuration","can-be-consumed","adhoc-resolution"],"backgroundTag":"gradle-detached-configuration-misuse","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}