{"record":{"id":"75062826ad97fb33","repo":"alibaba/spring-ai-alibaba","slug":"extra-state-key-collision-detected-key-oldv","errorCode":null,"errorMessage":"Extra state key collision detected: key='{}', oldValue='{}', newValue='{}', strategy={}, mergedValue='{}'","messagePattern":"Extra state key collision detected: key='(.+?)', oldValue='(.+?)', newValue='(.+?)', strategy=(.+?), mergedValue='(.+?)'","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/EnhancedParallelResultAggregator.java","lineNumber":202,"sourceCode":"\t * @param subGraphState the sub-graph's complete final state map\n\t * @param outputKeys all known sub-agent output keys to exclude\n\t * @param extraState the map to collect extra state entries into\n\t */\n\tprivate void extractExtraStateFromSubGraph(Map<String, Object> subGraphState,\n\t\t\t\t\t\t\t\t\t\t\t   Set<String> outputKeys,\n\t\t\t\t\t\t\t\t\t\t\t   Map<String, Object> extraState) {\n\t\tfor (Map.Entry<String, Object> entry : subGraphState.entrySet()) {\n\t\t\tString key = entry.getKey();\n\t\t\tif (isSystemKey(key) || outputKeys.contains(key)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (extraState.containsKey(key)) {\n\t\t\t\tObject oldValue = extraState.get(key);\n\t\t\t\tObject newValue = entry.getValue();\n\t\t\t\tKeyStrategy strategy = keyStrategies.getOrDefault(key, KeyStrategy.REPLACE);\n\t\t\t\tObject mergedValue = strategy.apply(oldValue, newValue);\n\t\t\t\textraState.put(key, mergedValue);\n\t\t\t\tlogger.warn(\"Extra state key collision detected: key='{}', \"\n\t\t\t\t\t\t+ \"oldValue='{}', newValue='{}', strategy={}, mergedValue='{}'\",\n\t\t\t\t\t\tkey, oldValue, newValue, strategy.getClass().getSimpleName(), mergedValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\textraState.put(key, entry.getValue());\n\t\t\t\tlogger.debug(\"Extracted extra state from sub-graph: {} = {}\", key, entry.getValue());\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Determines whether a key is a system/internal key that should not be propagated.\n\t * A key is considered internal if it starts with the system prefix ({@value SYSTEM_KEY_PREFIX})\n\t * or is present in the hardcoded {@link #SYSTEM_STATE_KEYS} fallback set.\n\t */\n\tprivate static boolean isSystemKey(String key) {\n\t\treturn key.startsWith(SYSTEM_KEY_PREFIX) || SYSTEM_STATE_KEYS.contains(key);\n\t}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/EnhancedParallelResultAggregator.java#L184-L220","documentation":"When extracting non-core state (extra state) from each sub-graph after parallel execution, extractExtraStateFromSubGraph detects that two sub-agents wrote the same extra key. It applies the configured KeyStrategy (default REPLACE, so last writer wins) and logs this warning including old/new/merged values.","triggerScenarios":"extractExtraStateFromSubGraph (called from apply) encounters a key already present in the accumulated extraState map while merging another sub-graph's state — e.g. multiple sub-agents sharing a default output key or both writing a common key like 'summary'.","commonSituations":"Sub-agents configured with identical outputKeys; a shared global key written by every agent (e.g. 'messages' handled elsewhere but custom keys like 'context'); copy-pasted agent configs.","solutions":["Give each sub-agent a unique outputKey so their extra state keys don't collide","Configure an explicit KeyStrategy (e.g. MERGE/APPEND) for keys intentionally shared","Use a dedicated ResultAggregator merge strategy that namespaces keys per sub-agent","Review the logged mergedValue to confirm last-writer-wins (REPLACE) is acceptable"],"exampleFix":"// before\nagentA = ReactAgent.builder().name(\"a\").outputKey(\"result\").build();\nagentB = ReactAgent.builder().name(\"b\").outputKey(\"result\").build(); // collision\n// after\nagentA = ReactAgent.builder().name(\"a\").outputKey(\"a_result\").build();\nagentB = ReactAgent.builder().name(\"b\").outputKey(\"b_result\").build();","handlingStrategy":"validation","validationCode":"Set<String> keys = new HashSet<>();\nfor (Agent s : subAgents) { String k = ((ReactAgent) s).getOutputKey(); if (!keys.add(k)) { throw new IllegalStateException(\"Duplicate outputKey across sub-agents: \" + k); } }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enforce unique outputKeys across parallel sub-agents at build time","Register explicit KeyStrategy entries for any intentionally shared keys","Prefer namespaced keys (agentName + '_result') over generic names like 'result'"],"tags":["state-collision","parallel-agent","key-strategy"],"backgroundTag":"conflicting-config-options","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"}