gradle/gradle · error · InvalidIvyPublicationException

artifact file is a directory: '%s'

Error message

artifact file is a directory: '%s'

What it means

Gradle's Ivy publishing pipeline validates every artifact immediately before upload. ValidatingIvyPublisher.checkCanPublish rejects any artifact whose File is a directory, because an Ivy repository coordinate must point to a downloadable regular file.

Source

Thrown at platforms/software/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publisher/ValidatingIvyPublisher.java:145

                        "multiple artifacts with the identical name, extension, type and classifier ('%s', %s', '%s', '%s').",
                        name, extension, type, classifier
                );
                throw new InvalidIvyPublicationException(publication.getName(), message);
            }
        }
    }

    private boolean hasCoordinates(IvyArtifact one, String name, String extension, String type, String classifier) {
        return Objects.equals(one.getName(), name)
                && Objects.equals(one.getType(), type)
                && Objects.equals(one.getExtension(), extension)
                && Objects.equals(one.getClassifier(), classifier);
    }

    private void checkCanPublish(String name, IvyArtifact artifact) {
        File artifactFile = artifact.getFile();
        if (artifactFile.isDirectory()) {
            throw new InvalidIvyPublicationException(name, String.format("artifact file is a directory: '%s'", artifactFile));
        }
    }

    private IvyFieldValidator field(IvyNormalizedPublication publication, String name, String value) {
        return new IvyFieldValidator(publication.getName(), name, value);
    }

    private static class IvyFieldValidator extends PublicationFieldValidator<IvyFieldValidator> {
        private IvyFieldValidator(String publicationName, String name, String value) {
            super(IvyFieldValidator.class, publicationName, name, value);
        }

        public IvyFieldValidator matches(String expectedValue) {
            if (!value.equals(expectedValue)) {
                throw new InvalidIvyPublicationException(publicationName,
                        String.format("supplied %s does not match ivy descriptor (cannot edit %1$s directly in the ivy descriptor file).", name)
                );
            }

View on GitHub (pinned to 534f27719b)

Solutions

  1. Attach a file-producing task or its output instead of a directory: publication.artifact(tasks.jar)
  2. If the content is a directory, package it first with a Zip/Jar task and publish that archive
  3. Add a doFirst guard on the publish task that fails fast when any artifact file is a directory

Example fix

// before
publication.artifact(file("$buildDir/resources/main")) // a directory

// after
publication.artifact(tasks.jar) // regular file produced by the build
Defensive patterns

Strategy: validation

Validate before calling

tasks.withType(PublishToIvyRepository).configureEach {
    doFirst {
        publication.artifacts.each { a ->
            if (a.file != null && a.file.isDirectory()) {
                throw new GradleException("Ivy artifact '${a.file}' is a directory - attach a file (e.g. tasks.jar) instead")
            }
        }
    }
}

Try / catch

try {
    project.tasks.named('publish').get().publish()
} catch (org.gradle.api.publish.ivy.InvalidIvyPublicationException e) {
    // message names the offending directory; fix the artifact definition, do not retry blindly
}

Prevention

When it happens

Trigger: An IvyPublication artifact whose file resolves to a directory: publication.artifact(someDir), IvyArtifact.setFile(dir), or attaching a task whose output is a directory (Copy/Sync destinationDir, sourceSets.main.output) instead of an archive output like the Jar task's archiveFile.

Common situations: Pointing the artifact at the resources or classes directory instead of the packaged jar; build logic migrated from the old artifacts{...} syntax where builtBy pointed at a directory-producing task; scripts that publish a folder of native libs directly.

Related errors


AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22). Data as JSON: /api/errors/60263c6e3391d51e. Report an issue: GitHub.