{"record":{"id":"d4d22b6bc176ff13","repo":"gradle/gradle","slug":"ivymoduledescriptor-implementations-must-implement","errorCode":null,"errorMessage":"ivyModuleDescriptor implementations must implement the '%s' interface, implementation '%s' does not","messagePattern":"ivyModuleDescriptor implementations must implement the '(.+?)' interface, implementation '(.+?)' does not","errorType":"exception","errorClass":"InvalidUserDataException","httpStatus":null,"severity":"error","filePath":"platforms/software/ivy/src/main/java/org/gradle/api/publish/ivy/tasks/GenerateIvyDescriptor.java","lineNumber":149,"sourceCode":"     * @since 1.4\n     */\n    @TaskAction\n    public void doGenerate() {\n        ivyDescriptorSpec.get().writeTo(getDestinationFile().get().getAsFile());\n    }\n\n    IvyDescriptorFileGenerator.DescriptorFileSpec computeIvyDescriptorFileSpec() {\n        IvyModuleDescriptorSpecInternal descriptorInternal = toIvyModuleDescriptorInternal(getDescriptor());\n        return IvyDescriptorFileGenerator.generateSpec(descriptorInternal);\n    }\n\n    private static IvyModuleDescriptorSpecInternal toIvyModuleDescriptorInternal(IvyModuleDescriptorSpec ivyModuleDescriptorSpec) {\n        if (ivyModuleDescriptorSpec == null) {\n            return null;\n        } else if (ivyModuleDescriptorSpec instanceof IvyModuleDescriptorSpecInternal) {\n            return (IvyModuleDescriptorSpecInternal) ivyModuleDescriptorSpec;\n        } else {\n            throw new InvalidUserDataException(\n                String.format(\n                    \"ivyModuleDescriptor implementations must implement the '%s' interface, implementation '%s' does not\",\n                    IvyModuleDescriptorSpecInternal.class.getName(),\n                    ivyModuleDescriptorSpec.getClass().getName()\n                )\n            );\n        }\n    }\n\n}\n","sourceCodeStart":131,"sourceCodeEnd":160,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/software/ivy/src/main/java/org/gradle/api/publish/ivy/tasks/GenerateIvyDescriptor.java#L131-L160","documentation":"GenerateIvyDescriptor expects its descriptor property to hold Gradle's internal implementation type (IvyModuleDescriptorSpecInternal). Assigning a custom object that only implements the public IvyModuleDescriptorSpec interface is rejected with this InvalidUserDataException.","triggerScenarios":"tasks.withType(GenerateIvyDescriptor) { descriptor = new MyCustomDescriptorSpec() } where the class implements only org.gradle.api.publish.ivy.IvyModuleDescriptorSpec; proxies or wrappers that recreate the descriptor via the public interface.","commonSituations":"Build logic copied from old forum posts that constructed custom descriptors; generic proxies (reflection, mapping frameworks) that strip the internal interface; migration from Gradle versions with looser typing.","solutions":["Do not replace the descriptor object - configure the existing one via descriptor.withXml, descriptor.status, descriptor.branch, descriptor.license","If you carry custom values, keep the default descriptor instance and copy the values onto it","Delete code that assigns to the descriptor property of the generate task"],"exampleFix":"// before\ngenerateDescriptorFileForIvyPublication.descriptor = new CustomIvyModuleDescriptorSpec()\n\n// after\npublishing.publications.ivy.descriptor.withXml {\n    asNode().info[0].appendNode('description', 'custom')\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def isGradleManagedDescriptor = { d ->\n    d instanceof org.gradle.api.publish.ivy.internal.publication.IvyModuleDescriptorSpecInternal\n}\nif (!isGradleManagedDescriptor(candidate)) {\n    throw new InvalidUserDataException('descriptor must be Gradle-internal; configure the default descriptor instead')\n}","tryCatchPattern":null,"preventionTips":["Never assign custom objects to the descriptor property of GenerateIvyDescriptor","Customize descriptors via descriptor.withXml and its properties","Treat internal interfaces (IvyModuleDescriptorSpecInternal) as Gradle implementation details"],"tags":["gradle","ivy","descriptor","internal-api","type-check"],"backgroundTag":"missing-internal-interface","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}