kestra-io/kestra · error · PebbleException

The 'subflow' function can only be used at flow-input…

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.

Solutions

  1. Use the Subflow TASK type instead for running subflows from within task properties: type: io.kestra.plugin.core.flow.Subflow.
  2. Move the subflow() call to a flow input's values field if you need it for the execute form.
  3. 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

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


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

Appendix: 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)