alibaba/spring-ai-alibaba · error · IllegalArgumentException

Cannot append to non-list value for key: {item.targetKey()}

Error message

Cannot append to non-list value for key: {item.targetKey()}

What it means

AssignerNode.apply throws this IllegalArgumentException when a write item uses the APPEND write mode but the current state value at targetKey exists and is not a List. Append semantics only work on list-valued state keys.

Source

Thrown at spring-boot-starters/spring-ai-alibaba-starter-builtin-nodes/src/main/java/com/alibaba/cloud/ai/graph/node/AssignerNode.java:102

						List<Object> newList = new ArrayList<>((List<?>) targetValue);
						if (value instanceof Collection<?> col) {
							newList.addAll(col);
						}
						else {
							newList.add(value);
						}
						yield newList;
					}
					else if (value != null) {
						if (value instanceof Collection<?> col) {
							yield new ArrayList<>(col);
						}
						else {
							yield new ArrayList<>(List.of(value));
						}
					}
					else {
						throw new IllegalArgumentException(
								"Cannot append to non-list value for key: " + item.targetKey());
					}
				}
				case CLEAR -> {
					if (targetValue instanceof List) {
						yield new ArrayList<>();
					}
					else if (targetValue instanceof Map) {
						yield new HashMap<>();
					}
					else if (targetValue instanceof String) {
						yield "";
					}
					else if (targetValue instanceof Number) {
						yield 0;
					}
					else {
						yield null;

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Ensure the target key is initialized as a List (or absent) before APPEND runs
  2. Change the rule's writeMode to OVERWRITE if replacing the scalar is intended
  3. Add a preceding AssignerNode step that sets the key to an empty list

Example fix

// before
AssignerNode.Item.builder().targetKey("history").writeMode(WriteMode.APPEND) // history holds a String
// after
// initialize history as a list first, or:
AssignerNode.Item.builder().targetKey("history").writeMode(WriteMode.OVERWRITE)
Defensive patterns

Strategy: type-guard

Validate before calling

Object cur = state.value(targetKey).orElse(null);
if (writeMode == WriteMode.APPEND && cur != null && !(cur instanceof List)) {
    throw new IllegalStateException(targetKey + " must hold a List for APPEND");
}

Type guard

static boolean isAppendable(Map<String,Object> state, String key) {
    Object v = state.get(key);
    return v == null || v instanceof List;
}

Try / catch

try {
    state = assignerNode.apply(state);
} catch (IllegalArgumentException e) {
    logger.error("Assigner append failed: {}", e.getMessage());
    state.put(targetKey, new ArrayList<>(List.of(newValue)));
}

Prevention

When it happens

Trigger: An assigner rule with writeMode=APPEND targets a key whose existing state value is a String, Map, or other non-List object, so the switch in apply cannot merge the new value.

Common situations: Key initialized elsewhere as a scalar (e.g. set by another node to a String) then targeted by APPEND; first write used OVERWRITE with a non-list value and a later APPEND hits it; state schema changed between workflow versions.

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


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/d63f857f095a9170. Report an issue: GitHub.