alibaba/spring-ai-alibaba · error · IllegalStateException
Edge '%s' is parallel
Error message
Edge '%s' is parallel
What it means
Edge.target() returns the single EdgeValue of a non-parallel edge. If the edge actually has multiple targets (a parallel/fan-out edge), it throws IllegalStateException "Edge '<sourceId>' is parallel" because asking for one target of a multi-target edge is meaningless.
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/internal/edge/Edge.java:55
* @param targets The targets value associated with the edge.
*/
public record Edge(String sourceId, List<EdgeValue> targets) {
public Edge(String sourceId, EdgeValue target) {
this(sourceId, List.of(target));
}
public Edge(String id) {
this(id, List.of());
}
public boolean isParallel() {
return targets.size() > 1;
}
public EdgeValue target() {
if (isParallel()) {
throw new IllegalStateException(format("Edge '%s' is parallel", sourceId));
}
return targets.get(0);
}
public boolean anyMatchByTargetId(String targetId) {
return targets().stream()
.anyMatch(v -> (v.id() != null) ? Objects.equals(v.id(), targetId)
: v.value().mappings().containsValue(targetId)
);
}
public Edge withSourceAndTargetIdsUpdated(Node node, Function<String, String> newSourceId,
Function<String, EdgeValue> newTarget) {
var newTargets = targets().stream().map(t -> t.withTargetIdsUpdated(newTarget)).toList();
return new Edge(newSourceId.apply(sourceId), newTargets);
View on GitHub (pinned to f82da0b50f)
Solutions
- Call edge.isParallel() first and use the targets list (EdgeValue with multiple entries) when it returns true.
- Use anyMatchByTargetId()/targets() APIs for parallel edges instead of target().
- Fix caller logic to branch per target when handling fan-out edges.
Example fix
// before
EdgeValue single = edge.target();
// after
if (edge.isParallel()) {
edge.targets().forEach(t -> handle(t));
} else {
handle(edge.target());
} Defensive patterns
Strategy: type-guard
Validate before calling
// Check edge arity before requesting a single target
if (edge.isParallel()) { throw new IllegalArgumentException("Use targets() for parallel edge " + edge.getSourceId()); } Type guard
Optional<EdgeValue> singleTarget(Edge e) { return e.isParallel() ? Optional.empty() : Optional.of(e.target()); } Try / catch
try { EdgeValue v = edge.target(); ... } catch (IllegalStateException e) { if (e.getMessage().endsWith("is parallel")) { edge.targets().forEach(this::handle); } } Prevention
- Always call isParallel() before target()
- Prefer targets()/anyMatchByTargetId() in generic traversal code
- Re-check edge assumptions after adding fan-out branches
When it happens
Trigger: Calling edgeValue.target() (or APIs like findPathEnd that rely on it) on an edge created with multiple targets, e.g. via addEdge("a", List.of(...)) or conditional edges resolving to several targets.
Common situations: Custom graph traversal code that assumes one target per edge; utility code walking edges after a fork was introduced; version changes where an edge previously single-target became parallel.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Currently Spring AI ToolResponseMessage only supports text t
- A2aRemoteAgent has not support schedule.
- LoopAgent must have only one subAgent, please use subAgent()
- cancel is not implemented yet!
- unwrap is not supported
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/7ebf0e1ab0de68cb.
Report an issue: GitHub.