kestra-io/kestra · error · IllegalArgumentException

Unable to read the file '{path}' as it is not an execution f

Error message

Unable to read the file '{path}' as it is not an execution file

What it means

extractNamespace() parses a kestra:/// internal storage URI expecting the shape .../executions/{executionId}/tasks/{taskId}/{taskRunId}/{fileName}. If the path after the kestra:// scheme does not match the EXECUTION_FILE regex, it throws IllegalArgumentException ('Unable to read the file ... as it is not an execution file'), wrapped by the catch into a PebbleException.

Source

Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/AbstractFileFunction.java:200

        if (args.get(NAMESPACE) != null && nsFileUri.getAuthority() != null) {
            throw new IllegalArgumentException("You cannot set a namespace both as the function argument and inside the URI");
        }

        // we will transform nsfile URI into a kestra URI so it is handled seamlessly by all functions
        String customNs = Optional.ofNullable((String) args.get(NAMESPACE)).orElse(nsFileUri.getAuthority());
        if (customNs != null) {
            namespaceService.get().checkAllowedNamespace(tenantId, customNs, tenantId, flow.get(NAMESPACE));
        }
        return Optional.ofNullable(customNs).orElse(flow.get(NAMESPACE));
    }

    @VisibleForTesting
    String extractNamespace(URI path) {
        // Extract namespace from the path, it should be of the form: kestra:///{namespace}/{flowId}/executions/{executionId}/tasks/{taskId}/{taskRunId}/{fileName}'
        // To extract the namespace, we must do it step by step as namespace and taskId can contain the words 'executions' and 'tasks'
        String namespace = path.toString().substring(KESTRA_SCHEME.length());
        if (!EXECUTION_FILE.matcher(namespace).matches()) {
            throw new IllegalArgumentException("Unable to read the file '" + path + "' as it is not an execution file");
        }
        // 1. remove everything after tasks
        namespace = namespace.substring(0, namespace.lastIndexOf("/tasks/"));
        // 2. remove everything after executions
        namespace = namespace.substring(0, namespace.lastIndexOf("/executions/"));
        // 3. remove the flowId
        namespace = namespace.substring(0, namespace.lastIndexOf('/'));
        // 4. replace '/' with '.'
        namespace = namespace.replace("/", ".");

        return namespace;
    }
}

View on GitHub (pinned to 823fada927)

Solutions

  1. Use a URI produced by a task output (outputs.*.uri) so the structure is guaranteed correct.
  2. For namespace files use the namespace:// scheme instead of a kestra:/// execution URI.
  3. Verify the URI contains /executions/<id>/tasks/<id>/<runId>/<file>.

Example fix

// before
{{ read('kestra:///company.team/_files/data.txt') }}
// after
{{ read('namespace:///company.team/data.txt') }}
Defensive patterns

Strategy: validation

Validate before calling

// Pebble: use the right scheme for the file type
{{ read('namespace:///company.team/data.txt') }}  // for namespace files
{{ read(outputs.task.uri) }}                       // for execution files

Prevention

When it happens

Trigger: Pointing read() at a kestra:/// URI that is a namespace file (/_files/...) or a trigger file, or a hand-built URI missing the executions/.../tasks/.../... structure, when the code path requires an execution-scoped file.

Common situations: Cross-namespace access to a file whose URI lacks the execution/tasks segments; truncated or copy-pasted internal storage URIs; confusing namespace files with execution files.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/ba0587751f3f689d. Report an issue: GitHub.