{"record":{"id":"bbad6a2cf64d1423","repo":"alibaba/spring-ai-alibaba","slug":"failed-to-execute-agent-tool-s-parentthreadid","errorCode":null,"errorMessage":"Failed to execute agent tool '%s' (parentThreadId=%s, input=%s): sub-agent invocation failed: ","messagePattern":"Failed to execute agent tool '(.+?)' \\(parentThreadId=(.+?), input=(.+?)\\): sub-agent invocation failed: ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/AgentTool.java","lineNumber":229,"sourceCode":"\t\t\ttry {\n\t\t\t\tif (parentConfigOpt.isPresent()) {\n\t\t\t\t\tRunnableConfig parentConfig = parentConfigOpt.get();\n\t\t\t\t\tRunnableConfig subConfig = RunnableConfig.builder(parentConfig)\n\t\t\t\t\t\t\t.threadId(parentConfig.threadId()\n\t\t\t\t\t\t\t\t\t.map(id -> id + \"_\" + agent.name())\n\t\t\t\t\t\t\t\t\t.orElseGet(agent::name))\n\t\t\t\t\t\t\t.nextNode(null)\n\t\t\t\t\t\t\t.checkPointId(null)\n\t\t\t\t\t\t\t.build();\n\t\t\t\t\tsubConfig.clearContext();\n\t\t\t\t\tresultState = agent.invoke(Map.of(\"messages\", messagesToAdd), subConfig);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tresultState = agent.invoke(Map.of(\"messages\", messagesToAdd));\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (GraphRunnerException e) {\n\t\t\t\tthrow buildExecutionException(actualInput, parentConfigOpt.orElse(null),\n\t\t\t\t\t\t\"sub-agent invocation failed: \" + e.getMessage(), e);\n\t\t\t}\n\t\t\tcatch (RuntimeException e) {\n\t\t\t\tthrow buildExecutionException(actualInput, parentConfigOpt.orElse(null),\n\t\t\t\t\t\t\"sub-agent invocation failed: \" + e.getMessage(), e);\n\t\t\t}\n\n\t\t\tOptional<List> messages = resultState.flatMap(overAllState -> overAllState.value(\"messages\", List.class));\n\t\t\tif (messages.isPresent()) {\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tList<Message> messageList = (List<Message>) messages.get();\n\t\t\t\tif (!messageList.isEmpty() && messageList.get(messageList.size() - 1) instanceof AssistantMessage assistantMessage) {\n\t\t\t\t\treturn assistantMessage;\n\t\t\t\t}\n\t\t\t\tthrow buildExecutionException(actualInput, parentConfigOpt.orElse(null),\n\t\t\t\t\t\t\"sub-agent returned no assistant message. Last message type: \"\n\t\t\t\t\t\t\t\t+ (messageList.isEmpty() ? \"<empty>\" : messageList.get(messageList.size() - 1).getMessageType()),\n\t\t\t\t\t\tnull);","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/AgentTool.java#L211-L247","documentation":"AgentTool.executeAgent wraps any GraphRunnerException thrown while invoking the sub-agent (ReactAgent.invoke) into a RuntimeException with the message 'Failed to execute agent tool ...: sub-agent invocation failed: <cause>'. The framework rethrows sub-agent execution failures as tool-call failures so the parent LLM sees the tool error. The root cause is in the wrapped GraphRunnerException message.","triggerScenarios":"Calling a sub-agent as a tool from a parent agent and the sub-agent's graph run fails with a GraphRunnerException — e.g. graph compile/executor error, checkpoint/ state read failure, node execution exception, or an invalid RunnableConfig derived from the parent's config.","commonSituations":"Sub-agent's underlying model call fails (bad API key, network, timeout) and propagates as a GraphRunnerException; sub-graph node throws; persistence/checkpoint backend unavailable for the derived threadId (parentThreadId + '_' + agent.name()); parent invoked via streaming context with an incompatible config.","solutions":["Read the chained cause in the exception — fix the underlying GraphRunnerException (model auth, network, node error) it reports.","Verify the sub-agent builds and runs standalone (agent.invoke with a fresh RunnableConfig) to isolate parent-context issues.","Check checkpoint/persistence connectivity for the derived threadId '<parentThreadId>_<agentName>' and that the parent thread exists.","Add retry/backoff on transient model or network failures inside the sub-agent's nodes, and validate model credentials before invoking."],"exampleFix":"// before: no failure handling in node\nString out = model.call(prompt);\n// after: guard model call inside sub-agent node\nString out;\ntry {\n    out = model.call(prompt);\n}\ncatch (RuntimeException e) {\n    throw new GraphRunnerException(\"model call failed: \" + e.getMessage(), e);\n}","handlingStrategy":"try-catch","validationCode":"// verify the sub-agent works standalone before wiring it as a tool\nOverAllState probe = reactAgent.invoke(Map.of(\"messages\", List.of(new UserMessage(\"ping\")))).orElse(null);\nif (probe == null || probe.value(\"messages\", List.class).isEmpty()) {\n    throw new IllegalStateException(\"Sub-agent \" + reactAgent.name() + \" not runnable\");\n}","typeGuard":"null","tryCatchPattern":"try {\n    assistantMessage = agentToolCallback.call(toolInput);\n}\ncatch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"sub-agent invocation failed\")) {\n        logger.warn(\"Sub-agent '{}' failed, falling back\", agentName, e.getCause());\n        // retry once or degrade gracefully\n    } else {\n        throw e;\n    }\n}","preventionTips":["Test each sub-agent standalone before composing it into a parent agent.","Verify model credentials and connectivity with a smoke call at startup.","Ensure the checkpoint store is reachable and the parent threadId is valid.","Add retry/backoff inside nodes for transient model/network errors."],"tags":["agent-framework","tool-execution","sub-agent","graph-runner"],"backgroundTag":"upstream-api-error","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}