kestra-io/kestra · error · IllegalArgumentException
Path must not contain '../'
Error message
Path must not contain '../'
What it means
Thrown by 'fileURI' inside getNamespaceFileURI() when the URI path string contains '../'. This is an explicit path-traversal guard: namespace file access is restricted to within the namespace, so escaping via parent-directory segments is rejected before any storage operation.
Source
Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/FileURIFunction.java:57
defaults.put(NAMESPACE, null);
defaults.put(REVISION, null);
return defaults;
}
@Override
protected Object fileFunction(EvaluationContext context, URI path, String namespace, String tenantId, Map<String, Object> args) throws IOException {
return switch (path.getScheme()) {
case StorageContext.KESTRA_SCHEME -> path.toString();
case LocalPath.FILE_SCHEME -> path.toString();
case Namespace.NAMESPACE_FILE_SCHEME -> getNamespaceFileURI(path, namespace, tenantId, args);
default -> throw new IllegalArgumentException(SCHEME_NOT_SUPPORTED_ERROR.formatted(path));
};
}
private String getNamespaceFileURI(URI path, String namespace, String tenantId, Map<String, Object> args) throws IOException {
String pathStr = path.getPath();
if (pathStr.contains("../")) {
throw new IllegalArgumentException("Path must not contain '../'");
}
Namespace namespaceStorage = namespaceFactory.get().of(tenantId, namespace, storageInterface.get());
Path filePath = NamespaceFile.normalize(Path.of(pathStr));
if (args.containsKey(REVISION)) {
Integer revision;
try {
revision = Integer.parseInt(args.get(REVISION).toString());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("The 'fileURI' function expects the 'revision' argument to be a valid integer.");
}
try {
namespaceStorage.getFileContent(filePath, revision).close();
} catch (FileNotFoundException e) {
throw new FileNotFoundException("Revision " + revision + " of file '" + filePath + "' was not found in namespace '" + namespace + "'.");
}
NamespaceFile namespaceFile = NamespaceFile.of(namespace, filePath, revision);
return namespaceFile.uri().toString();View on GitHub (pinned to 823fada927)
Solutions
- Remove any '../' from the path; reference files only within the target namespace.
- If the path is built from user input, sanitize/normalize it (resolve and confirm it stays under the namespace root) before passing it to fileURI().
- Move the needed file into the correct namespace instead of traversing out.
Example fix
# before
uri: "{{ fileURI('namespace:///../shared/secret.yaml') }}"
# after - reference the file within the correct namespace
uri: "{{ fileURI('namespace:///shared/secret.yaml') }}" Defensive patterns
Strategy: validation
Validate before calling
# Reject '../' in the path before calling fileURI().
# {{ (not (path contains '../')) ? fileURI(path) : null }} Prevention
- Never include '../' in namespace file paths.
- Sanitize paths built from user/flow input before passing to fileURI().
- Reference files only within the target namespace.
- Normalize and verify the path stays under the namespace root.
When it happens
Trigger: Calling fileURI() with a namespace file path that includes '../' to climb above the namespace root, e.g. namespace:///../secret or a path built from user input that injects '../'.
Common situations: Constructing a namespace file path dynamically from untrusted user input (flow inputs) without sanitizing; attempting to read a file outside the current namespace; copy-pasting a filesystem-relative path into a namespace URI.
Related errors
- The 'fileURI' function expects the 'revision' argument to be
- Cannot process the URI %s: scheme not supported.
- Revision {revision} of file '{filePath}' was not found in na
- Cannot process the URI %s: scheme not supported.
- Cannot process the URI %s: scheme not supported.
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/8593bbd9bfa302d4.
Report an issue: GitHub.