alibaba/spring-ai-alibaba · error · IllegalArgumentException
Cannot merge incompatible types: {} and {}
Error message
Cannot merge incompatible types: {} and {} What it means
The default apply() merge strategy merges maps generically, but for other values it requires oldValue and newValue to be the same class; if classes differ it throws IllegalArgumentException listing both class names. This guards state channel reducers from silently combining incompatible value shapes during graph state updates.
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/state/strategy/MergeStrategy.java:59
newValue = newValueOptional.orElse(null);
}
if (newValue == null) {
return oldValue;
}
if (oldValue == null) {
return newValue;
}
if (oldValue instanceof Map && newValue instanceof Map) {
Map<Object, Object> mergedMap = new HashMap<>((Map<?, ?>) oldValue);
mergedMap.putAll((Map<?, ?>) newValue);
return mergedMap;
}
if (oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException(
"Cannot merge incompatible types: " +
oldValue.getClass().getName() + " and " + newValue.getClass().getName()
);
}
if (shouldMergeObjectFields(oldValue.getClass())) {
return mergeObjectFields(oldValue, newValue).orElse(newValue);
}
return newValue;
}
private Optional<Object> mergeObjectFields(Object oldValue, Object newValue) {
try {
Object mergedValue = createInstance(oldValue.getClass());
for (Field field : mergeableFields(oldValue.getClass())) {
field.setAccessible(true);
Object oldFieldValue = field.get(oldValue);View on GitHub (pinned to f82da0b50f)
Solutions
- Make all writers to the channel return the same type
- Add a custom MergeStrategy/reducer for that channel that handles both types
- Coerce/convert values to a common type before returning them from nodes
Example fix
// before
state.put("result", "text-summary"); // node A
state.put("result", Map.of("k","v")); // node B -> throws
// after
// both nodes emit the same shape, e.g.
state.put("result", Map.of("summary", "text-summary")); Defensive patterns
Strategy: try-catch
Validate before calling
if (oldValue != null && newValue != null && oldValue.getClass() != newValue.getClass()) { /* coerce or route to custom reducer first */ } Try / catch
try { merged = strategy.apply(channel, oldValue, newValue); } catch (IllegalArgumentException e) { log.error("Channel {} type conflict: {}", channel, e.getMessage()); } Prevention
- Enforce a single result type per state channel
- Document the channel schema for all node authors
- Write custom reducers for heterogeneous channels
When it happens
Trigger: Two graph nodes write to the same state channel in one superstep and return values of different types (e.g. a Map and a String, or Integer and Long); a custom reducer delegates to this strategy with heterogeneous values.
Common situations: Parallel/branching workflows where branches emit different result types into a shared key; refactoring a node's return type without updating other writers; numeric boxing differences (Integer vs Long) across nodes.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- No default output or error next node provided
- Sub-agents must be BaseAgent
- Loop flow requires a valid LoopStrategy. Got: null
- Routing sub-agents must be BaseAgent for merge support
- Human feedback metadata must be of type InterruptionMetadata
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/e8cce6d9c8fdefea.
Report an issue: GitHub.