{"record":{"id":"c4d776b927242aa4","repo":"kestra-io/kestra","slug":"subflow-s-s-ended-in-state-s-execution-s","errorCode":null,"errorMessage":"Subflow '%s'.'%s' ended in state %s (execution %s).","messagePattern":"Subflow '(.+?)'\\.'(.+?)' ended in state (.+?) \\(execution (.+?)\\)\\.","errorType":"exception","errorClass":"PebbleException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/kestra/core/runners/pebble/functions/SubflowFunction.java","lineNumber":191,"sourceCode":"                    targetFlow,\n                    (f, e) -> flowInputOutput.get().readExecutionInputs(f, e, inputs),\n                    labels,\n                    Optional.empty()\n                );\n            } catch (Exception e) {\n                throw new PebbleException(e, \"Invalid inputs for subflow '\" + namespace + \"'.'\" + id + \"': \" + e.getMessage(), lineNumber, self.getName());\n            }\n\n            Execution terminated;\n            try {\n                terminated = executionService.get().runAndWait(execution, targetFlow, timeout);\n            } catch (Exception e) {\n                throw new PebbleException(e, \"Failed to run subflow '\" + namespace + \"'.'\" + id + \"': \" + e.getMessage(), lineNumber, self.getName());\n            }\n\n            State.Type state = terminated.getState().getCurrent();\n            if (state != State.Type.SUCCESS && state != State.Type.WARNING) {\n                throw new PebbleException(\n                    null, \"Subflow '\" + namespace + \"'.'\" + id + \"' ended in state \" + state\n                        + \" (execution \" + terminated.getId() + \").\",\n                    lineNumber, self.getName()\n                );\n            }\n\n            return Result.of(terminated);\n        } finally {\n            int current = DEPTH.get() - 1;\n            if (current <= 0) {\n                DEPTH.remove();\n            } else {\n                DEPTH.set(current);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/kestra-io/kestra/blob/823fada9274c4f9c251ea0a516460a4f7d958032/core/src/main/java/io/kestra/core/runners/pebble/functions/SubflowFunction.java#L173-L209","documentation":"After runAndWait returns a terminal execution, the subflow() function checks the state. Only SUCCESS and WARNING are considered acceptable outcomes. Any other terminal state (FAILED, KILLED, CANCELLED, etc.) causes the function to throw, including the execution ID so the user can look up the failure details in the UI. This is by design: subflow() is a synchronous call and a failed child flow should surface as an error to the caller.","triggerScenarios":"The target flow runs to completion but ends in FAILED, KILLED, CANCELLED, or another non-success state. A task inside the target flow fails, causing the flow to fail. The target flow is killed manually while the subflow() call is waiting. The target flow has no tasks or has a configuration that results in a non-success terminal state.","commonSituations":"The target flow has a bug or a failing task. An external dependency (API, database) the target flow depends on is unavailable. The target flow was manually killed by a user. Resource constraints cause a task to fail.","solutions":["Look up the execution ID from the error message in the Kestra UI to find the root cause of the failure.","Fix the failing task(s) in the target flow.","If the failure is expected or intermittent, consider adding retry logic or error handling in the target flow.","If you want to tolerate failures, consider using the Subflow task type with wait=true and checks outputs.state instead of subflow()."],"exampleFix":"# The error includes the execution ID, e.g.:\n# \"Subflow 'company.team'.'child' ended in state FAILED (execution aBcDeFgHiJ).\"\n# Look up that execution ID in the Kestra UI to find the failed task and fix it.\n\n# If you need to tolerate subflow failures, use the Subflow task instead:\n- id: run_child\n  type: io.kestra.plugin.core.flow.Subflow\n  namespace: company.team\n  flowId: child\n  wait: true\n  outputs:\n    state: \"{{ outputs.run_child.executionId | lookupState }}\"\n# Then check outputs.run_child.state before proceeding","handlingStrategy":"validation","validationCode":"# Before relying on subflow(), ensure the target flow is robust:\n#   - Test it independently via the Kestra execute form\n#   - Add error handling (restart, retry) within the target flow\n# If you need to tolerate non-success states, use the Subflow task instead:\n# - id: run_child\n#   type: io.kestra.plugin.core.flow.Subflow\n#   namespace: ns\n#   flowId: child\n#   wait: true\n# Then check {{ outputs.run_child.state }} and branch accordingly.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Test target flows independently before wiring them into subflow() calls.","Add retry/restart logic in the target flow for transient failures.","If failure tolerance is needed, use the Subflow task type and inspect the execution state.","Monitor child execution logs to catch regressions early."],"tags":["pebble","subflow","execution-state","failed","terminal-state"],"backgroundTag":null,"analyzedSha":"823fada9274c4f9c251ea0a516460a4f7d958032","analyzedAt":"2026-08-14T06:15:17.947Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}