alibaba/spring-ai-alibaba · warning
Extra state key collision detected: key=
Error message
Extra state key collision detected: key='{}', oldValue='{}', newValue='{}', strategy={}, mergedValue='{}' What it means
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.
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
Example fix
// before
agentA = ReactAgent.builder().name("a").outputKey("result").build();
agentB = ReactAgent.builder().name("b").outputKey("result").build(); // collision
// after
agentA = ReactAgent.builder().name("a").outputKey("a_result").build();
agentB = ReactAgent.builder().name("b").outputKey("b_result").build(); Defensive patterns
Strategy: validation
Validate before calling
Set<String> keys = new HashSet<>();
for (Agent s : subAgents) { String k = ((ReactAgent) s).getOutputKey(); if (!keys.add(k)) { throw new IllegalStateException("Duplicate outputKey across sub-agents: " + k); } } Prevention
- 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'
When it happens
Trigger: 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'.
Common situations: 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.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- No output found for sub-agent
- Parallel flow requires at least 2 sub-agents for meaningful…
- Parallel flow requires at least one sub-agent
- Sub-agent ' ' has no outputKey defined. This may cause data…
- Sub-agents must be BaseAgent
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/75062826ad97fb33.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/EnhancedParallelResultAggregator.java:202
* @param subGraphState the sub-graph's complete final state map
* @param outputKeys all known sub-agent output keys to exclude
* @param extraState the map to collect extra state entries into
*/
private void extractExtraStateFromSubGraph(Map<String, Object> subGraphState,
Set<String> outputKeys,
Map<String, Object> extraState) {
for (Map.Entry<String, Object> entry : subGraphState.entrySet()) {
String key = entry.getKey();
if (isSystemKey(key) || outputKeys.contains(key)) {
continue;
}
if (extraState.containsKey(key)) {
Object oldValue = extraState.get(key);
Object newValue = entry.getValue();
KeyStrategy strategy = keyStrategies.getOrDefault(key, KeyStrategy.REPLACE);
Object mergedValue = strategy.apply(oldValue, newValue);
extraState.put(key, mergedValue);
logger.warn("Extra state key collision detected: key='{}', "
+ "oldValue='{}', newValue='{}', strategy={}, mergedValue='{}'",
key, oldValue, newValue, strategy.getClass().getSimpleName(), mergedValue);
}
else {
extraState.put(key, entry.getValue());
logger.debug("Extracted extra state from sub-graph: {} = {}", key, entry.getValue());
}
}
}
/**
* Determines whether a key is a system/internal key that should not be propagated.
* A key is considered internal if it starts with the system prefix ({@value SYSTEM_KEY_PREFIX})
* or is present in the hardcoded {@link #SYSTEM_STATE_KEYS} fallback set.
*/
private static boolean isSystemKey(String key) {
return key.startsWith(SYSTEM_KEY_PREFIX) || SYSTEM_STATE_KEYS.contains(key);
}View on GitHub (pinned to f82da0b50f)