alibaba/spring-ai-alibaba · error
Last message is not an AssistantMessage, cannot process…
Error message
Last message is not an AssistantMessage, cannot process human feedback.
What it means
HumanInTheLoopHook.afterModel logs a warning when feedback rejection is requested but the last message is not an AssistantMessage — tool-call rewriting/removal can only apply to assistant messages carrying tool calls, so the feedback cannot be processed.
Solutions
- Ensure the interrupt happened after a model response containing tool calls
- Verify message ordering in state before resuming with feedback
- Ignore for non-tool-call interruptions; proceed without message rewriting
Defensive patterns
Strategy: type-guard
When it happens
Trigger: Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/hook/hip/HumanInTheLoopHook.java:141 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/ce7707b458d3ba01.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/hook/hip/HumanInTheLoopHook.java:141
newMessages.add(AssistantMessage.builder()
.content(assistantMessage.getText())
.properties(assistantMessage.getMetadata())
.toolCalls(newToolCalls)
.media(assistantMessage.getMedia())
.build());
newMessages.add(new RemoveByHash<>(assistantMessage));
}
// ToolResponseMessages must be added after AssistantMessage
if (!rejectedMessage.getResponses().isEmpty()) {
newMessages.add(rejectedMessage);
}
updates.put("messages", newMessages);
return CompletableFuture.completedFuture(updates);
}
else {
log.warn("Last message is not an AssistantMessage, cannot process human feedback.");
}
return CompletableFuture.completedFuture(Map.of());
}
@Override
public Optional<InterruptionMetadata> interrupt(String nodeId, OverAllState state, RunnableConfig config) {
AssistantMessage lastMessage = getLastAssistantMessage(state);
if (lastMessage == null || !lastMessage.hasToolCalls()) {
return Optional.empty();
}
Optional<Object> feedback = config.metadata(RunnableConfig.HUMAN_FEEDBACK_METADATA_KEY);
if (feedback.isPresent()) {
if (!(feedback.get() instanceof InterruptionMetadata)) {
throw new IllegalArgumentException("Human feedback metadata must be of type InterruptionMetadata.");
}View on GitHub (pinned to f82da0b50f)