{"record":{"id":"43a78a89b225ee28","repo":"alibaba/spring-ai-alibaba","slug":"duplicate-hook-instances-found","errorCode":null,"errorMessage":"Duplicate hook instances found","messagePattern":"Duplicate hook instances found","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/ReactAgent.java","lineNumber":326,"sourceCode":"\t}\n\n\t@Override\n\tprotected StateGraph initGraph() throws GraphStateException {\n\n\t\tif (hooks == null) {\n\t\t\thooks = new ArrayList<>();\n\t\t}\n\n\t\t// Always inject default InstructionAgentHook so instruction is handled in beforeAgent\n\t\tList<Hook> effectiveHooks = new ArrayList<>();\n\t\teffectiveHooks.add(InstructionAgentHook.create());\n\t\teffectiveHooks.addAll(hooks);\n\n\t\t// Validate hook uniqueness\n\t\tSet<String> hookNames = new HashSet<>();\n\t\tfor (Hook hook : effectiveHooks) {\n\t\t\tif (!hookNames.add(Hook.getFullHookName(hook))) {\n\t\t\t\tthrow new IllegalArgumentException(\"Duplicate hook instances found\");\n\t\t\t}\n\n\t\t\t// set agent name to every hook node.\n\t\t\thook.setAgentName(this.name);\n\t\t\thook.setAgent(this);\n\t\t}\n\n\t\t// Create graph with state serializer\n\t\tStateGraph graph = new StateGraph(name, buildMessagesKeyStrategyFactory(effectiveHooks), stateSerializer);\n\n\t\tgraph.addNode(AGENT_MODEL_NAME, node_async(this.llmNode));\n\t\tif (hasTools) {\n\t\t\tgraph.addNode(AGENT_TOOL_NAME, node_async(this.toolNode));\n\t\t}\n\n\t\t// some hooks may need tools so they can do some initialization/cleanup on start/end of agent loop\n\t\tsetupToolsForHooks(effectiveHooks, toolNode);\n","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/ReactAgent.java#L308-L344","documentation":"ReactAgent.initGraph validates that all effective hooks (hooks from sub-agents plus this agent's own hooks) have unique full hook names, throwing IllegalArgumentException on the first duplicate. Duplicate hooks would cause the same lifecycle logic to run twice per node.","triggerScenarios":"Registering the same Hook instance (or two hooks sharing the same full hook name) more than once — e.g. an interceptor added to both a sub-agent and the parent so it appears twice in effectiveHooks when building the graph.","commonSituations":"Sharing one interceptor/hook object across nested agents in multi-agent setups; programmatically appending hooks that were already inherited from sub-agents.","solutions":["Remove the duplicate hook registration — register each hook at a single level of the agent hierarchy.","If distinct behavior is needed, create a second Hook instance/class with a different full hook name.","Deduplicate before build(): collect hooks into a Set keyed by Hook.getFullHookName(hook)."],"exampleFix":"// before\nbuilder.hooks(myInterceptor);\nsubAgentBuilder.hooks(myInterceptor); // same instance propagates up\n// after\nbuilder.hooks(myInterceptor); // register only once, on the parent","handlingStrategy":"validation","validationCode":"Set<String> seen = new HashSet<>();\nfor (Hook h : allHooks) {\n    if (!seen.add(Hook.getFullHookName(h)))\n        throw new IllegalArgumentException(\"Duplicate hook registered: \" + Hook.getFullHookName(h));\n}","typeGuard":null,"tryCatchPattern":"try { agent = builder.build(); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"Duplicate hook\")) { log.error(\"Register each hook once; check nested agents sharing hook instances\"); } throw e; }","preventionTips":["Register hooks at exactly one level of the agent hierarchy.","Deduplicate hook lists with a Set keyed by getFullHookName before building.","Avoid sharing one hook instance between parent and sub-agent builders."],"tags":["hooks","duplicate","illegal-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}