{"record":{"id":"29696c1cb14aaba3","repo":"alibaba/spring-ai-alibaba","slug":"gotonodes-cannot-be-empty","errorCode":null,"errorMessage":"gotoNodes cannot be empty","messagePattern":"gotoNodes cannot be empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/action/MultiCommand.java","lineNumber":35,"sourceCode":"\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * Represents a command that can route to multiple nodes for parallel execution.\n * This is used when a conditional edge action returns multiple target nodes.\n *\n * @param gotoNodes A list of node identifiers to execute in parallel\n * @param update A map containing key-value pairs representing updates to be merged into the current state\n */\npublic record MultiCommand(List<String> gotoNodes, Map<String, Object> update) {\n\n\tpublic MultiCommand {\n\t\tObjects.requireNonNull(gotoNodes, \"gotoNodes cannot be null\");\n\t\tObjects.requireNonNull(update, \"update cannot be null\");\n\t\tif (gotoNodes.isEmpty()) {\n\t\t\tthrow new IllegalArgumentException(\"gotoNodes cannot be empty\");\n\t\t}\n\t}\n\n\t/**\n\t * Constructs a MultiCommand that specifies only the next nodes to transition to,\n\t * with no state updates.\n\t * @param gotoNodes The list of nodes to transition to. Cannot be empty.\n\t */\n\tpublic MultiCommand(List<String> gotoNodes) {\n\t\tthis(gotoNodes, Map.of());\n\t}\n\n\t/**\n\t * Checks if this MultiCommand represents a single node (for backward compatibility).\n\t * @return true if there's only one node, false otherwise\n\t */\n\tpublic boolean isSingleNode() {\n\t\treturn gotoNodes.size() == 1;","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/action/MultiCommand.java#L17-L53","documentation":"MultiCommand is a record representing multiple goto targets plus state updates. Its compact constructor rejects a null or empty gotoNodes list with NullPointerException or IllegalArgumentException, because a command that goes nowhere is meaningless for graph routing.","triggerScenarios":"Invoking new MultiCommand(List.of(), updates) or new MultiCommand(null, updates), or a node action building a MultiCommand from a router that returns no branches.","commonSituations":"MultiRoute node actions whose branching logic computed an empty destination list (e.g. map lookup miss, filter that removed all candidates); Java records deserialization passing empty lists.","solutions":["Ensure the routing logic always returns at least one target node id before constructing MultiCommand","Default to a fallback node id when the computed branch list is empty","Use Command (single target) instead when only one destination is possible","Validate upstream state that feeds the routing decision before building the command"],"exampleFix":"// before\nreturn new MultiCommand(routeTargets(state), state.data()); // may be empty\n// after\nList<String> targets = routeTargets(state);\nif (targets.isEmpty()) { targets = List.of(\"fallback\"); }\nreturn new MultiCommand(targets, state.data());","handlingStrategy":"validation","validationCode":"List<String> targets = computeGotoNodes(state);\nObjects.requireNonNull(targets, \"gotoNodes\");\nif (targets.isEmpty()) throw new IllegalArgumentException(\"router produced no target nodes\");\nreturn new MultiCommand(targets, state.data());","typeGuard":"static boolean isUsable(MultiCommandInput in) { return in.gotoNodes() != null && !in.gotoNodes().isEmpty(); }","tryCatchPattern":"try { return new MultiCommand(gotoNodes, update); } catch (IllegalArgumentException e) { return new MultiCommand(List.of(\"fallback\"), update); }","preventionTips":["Default empty routing results to a fallback node","Never pass Optional.empty-derived or filtered-empty lists straight into MultiCommand","Unit-test routers for every state shape"],"tags":["graph","routing","argument"],"backgroundTag":"empty-required-field","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"}