kestra-io/kestra · error · PebbleException
The 'subflow' function can only be used at flow-input render
Error message
The 'subflow' function can only be used at flow-input render time (e.g. an input's 'values'); it is not supported inside task or trigger properties.
What it means
The subflow() function is designed exclusively for populating a flow input's 'values' at execute-form render time on the webserver, because it blocks synchronously until the child execution terminates. When the evaluation context contains a top-level 'taskrun' or 'trigger' variable, rendering is happening inside a task or trigger property — contexts that may execute on a worker thread. Blocking a worker thread on a child execution can deadlock the worker when slots are exhausted, so the function refuses to run.
Source
Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/SubflowFunction.java:108
public Map<String, String> getArgumentDefaults() {
HashMap<String, String> defaults = new HashMap<>();
defaults.put(NAMESPACE_ARG, "'company.team'");
defaults.put(ID_ARG, "'my_subflow'");
defaults.put(INPUTS_ARG, "{'my_input': 'my_value'}");
defaults.put(REVISION_ARG, null);
defaults.put(LABELS_ARG, null);
defaults.put(TIMEOUT_ARG, null);
return defaults;
}
@SuppressWarnings("unchecked")
@Override
public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
// The call blocks until the subflow terminates: only allow it where rendering happens on a
// blocking-friendly thread (flow-input rendering on the webserver). A top-level 'taskrun' or
// 'trigger' variable means we are rendering a task or trigger property, which may run on a worker.
if (context.getVariable("taskrun") != null || context.getVariable("trigger") != null) {
throw new PebbleException(
null, "The 'subflow' function can only be used at flow-input render time (e.g. an input's 'values'); it is not supported inside task or trigger properties.", lineNumber,
self.getName()
);
}
String namespace = (String) args.get(NAMESPACE_ARG);
String id = (String) args.get(ID_ARG);
if (namespace == null || id == null) {
throw new PebbleException(null, "The 'subflow' function expects the arguments 'namespace' and 'id'.", lineNumber, self.getName());
}
Map<String, String> flow = (Map<String, String>) context.getVariable("flow");
if (flow == null) {
throw new PebbleException(
null, "The 'subflow' function can only be used in a flow context (e.g. an input's 'values'); the caller flow could not be resolved.", lineNumber, self.getName()
);
}
String tenantId = flow.get("tenantId");View on GitHub (pinned to 823fada927)
Solutions
- Use the Subflow TASK type instead for running subflows from within task properties: type: io.kestra.plugin.core.flow.Subflow.
- Move the subflow() call to a flow input's values field if you need it for the execute form.
- Access subflow outputs via the Subflow task's outputs ({{ outputs.subflow_task_id.outputs }}) rather than calling subflow() inline.
Example fix
# before — subflow() inside a task property (illegal)
tasks:
- id: my_task
type: io.kestra.plugin.core.log.Log
message: "{{ subflow(namespace='company.team', id='child') }}"
# after — use the Subflow task type
tasks:
- id: run_child
type: io.kestra.plugin.core.flow.Subflow
namespace: company.team
flowId: child
wait: true
- id: log_result
type: io.kestra.plugin.core.log.Log
message: "{{ outputs.run_child.outputs.my_output }}" Defensive patterns
Strategy: validation
Validate before calling
# Only use subflow() inside a flow input's 'values' field. # For running subflows from tasks, use the Subflow task type: # - id: run_child # type: io.kestra.plugin.core.flow.Subflow # namespace: company.team # flowId: child # wait: true # Never place subflow() inside task or trigger properties.
Prevention
- Reserve subflow() exclusively for flow input 'values' fields.
- Use the Subflow task type (io.kestra.plugin.core.flow.Subflow) for task-level subflow execution.
- Read the function Javadoc: it documents the render-time restriction clearly.
- During code review, flag any subflow() call that appears inside a task or trigger definition.
When it happens
Trigger: Using {{ subflow(namespace='x', id='y') }} inside a task property (e.g., a script command, a task input) or a trigger property. The Pebble renderer encounters a 'taskrun' or 'trigger' variable in scope and the subflow() call is evaluated in that context.
Common situations: Confusing subflow() (a synchronous blocking call for input values) with the Subflow task type (io.kestra.plugin.core.flow.Subflow) which is the correct mechanism for running a subflow from within a task. Trying to use subflow() to get outputs mid-execution in a task. Copy-pasting a subflow() call from an input definition into a task definition.
Related errors
- The 'subflow' function can only be used in a flow context (e
- The 'errorLogs' function can only be used in the Worker as i
- Unable to fetch error logs
- The 'subflow' function expects the arguments 'namespace' and
- The 'subflow' function exceeded the maximum nesting depth of
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/e36273f1ac23b549.
Report an issue: GitHub.