gradle/gradle · error · InvalidUserDataException

Transform output %s must be a part of the input artifact or

Error message

Transform output %s must be a part of the input artifact or refer to a relative path.

What it means

TransformOutputs.file()/dir() resolve their argument against the transform's dedicated output directory. When the resolved File is absolute and lies neither under the output directory nor inside the input artifact, OutputTypeInferringBuilder.addOutput rejects it immediately with this InvalidUserDataException - artifact transforms must keep all outputs inside their workspace to stay hermetic and cacheable. The full offending path is included in the message.

Source

Thrown at platforms/software/dependency-management/src/main/java/org/gradle/api/internal/artifacts/transform/TransformExecutionResult.java:285

         * Adds an output location to the result.
         *
         * @param workspaceAction an action to run when the output is a produced output in the workspace.
         */
        public void addOutput(File output, Consumer<File> workspaceAction) {
            if (output.equals(inputArtifact)) {
                delegate.addEntireInputArtifact();
            } else if (output.equals(outputDir)) {
                delegate.addProducedOutput("");
                workspaceAction.accept(output);
            } else if (output.getPath().startsWith(outputDirPrefix)) {
                String relativePath = RelativePath.parse(true, output.getPath().substring(outputDirPrefix.length())).getPathString();
                delegate.addProducedOutput(relativePath);
                workspaceAction.accept(output);
            } else if (output.getPath().startsWith(inputArtifactPrefix)) {
                String relativePath = RelativePath.parse(true, output.getPath().substring(inputArtifactPrefix.length())).getPathString();
                delegate.addPartOfInputArtifact(relativePath);
            } else {
                throw new InvalidUserDataException("Transform output " + output.getPath() + " must be a part of the input artifact or refer to a relative path.");
            }
        }

        public TransformExecutionResult build() {
            return delegate.build();
        }
    }
}

View on GitHub (pinned to 534f27719b)

Solutions

  1. Always pass RELATIVE paths to outputs.file()/dir() (e.g. outputs.file('classes.jar')) so they resolve inside the transform workspace
  2. If you unpack to a scratch dir first, copy the final artifact into the file returned by outputs.file('name') before returning
  3. Never register outputs built from project.file(...), java.io.tmpdir, or other absolute prefixes

Example fix

// before
void transform(TransformOutputs outputs) {
    def tmp = File.createTempDir()
    unzip(inputFile, tmp)
    outputs.file(new File(tmp, "classes.jar")) // absolute path outside workspace -> error
}

// after
void transform(TransformOutputs outputs) {
    def out = outputs.file("classes.jar")   // relative -> inside workspace
    unzipToZip(inputFile, out)               // write directly into declared output
}
Defensive patterns

Strategy: validation

Validate before calling

// inside transform(): guard every absolute candidate before handing it to outputs.file()/dir()
static boolean insideWorkspace(File f, File outputDir, File inputArtifact) {
    def p = f.toPath().normalize()
    p.startsWith(outputDir.toPath()) || p.startsWith(inputArtifact.toPath())
}
// or simply never pass absolute paths: outputs.file("classes.jar")

Prevention

When it happens

Trigger: Calling outputs.file(new File('/tmp/result.jar')), outputs.file(project.file('build/out.jar')), or writing results into java.io.tmpdir and registering files from there - any absolute location outside outputDir and outside the input artifact's path; also File.createTempDir() based scratch directories reported as outputs.

Common situations: Transform code copied from a Task that wrote to the project layout; unzip/explode helpers that use a temp directory; returning a path computed from system properties or user.dir instead of the registered output location.

Related errors


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