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
- Always pass RELATIVE paths to outputs.file()/dir() (e.g. outputs.file('classes.jar')) so they resolve inside the transform workspace
- If you unpack to a scratch dir first, copy the final artifact into the file returned by outputs.file('name') before returning
- 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
- Only ever pass relative paths to TransformOutputs.file()/dir()
- Copy scratch-dir results into the registered output before returning
- Ban project.file(...), java.io.tmpdir, and user.dir from transform code in review
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
- Unexpected marker file: {markerFile} in instrumented buildsc
- Error while evaluating property '%s' of %s
- No service of type %s available.
- Could not isolate parameters %s of artifact transform %s
- Transform output file %s must be a file, but is not.
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/1d64274d330a6cc4.
Report an issue: GitHub.