alibaba/spring-ai-alibaba · error · ResponseStatusException
threadId cannot be null or empty
Error message
threadId cannot be null or empty
What it means
The SSE run endpoint rejects requests whose threadId is null or blank. Spring AI Alibaba's ExecutionController requires a threadId to identify the conversation/checkpoint stream, so it returns a 400 ResponseStatusException wrapped in a Flux error before any agent loading happens.
Source
Thrown at spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/controller/ExecutionController.java:171
* @return A Flux that will stream events to the client in standard SSE format.
*/
@PostMapping(value = "/run_sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> agentRunSse(@RequestBody AgentRunRequest request) {
if (request.appName == null || request.appName.trim().isEmpty()) {
log.warn(
"appName cannot be null or empty in SSE request for appName: {}, session: {}",
request.appName,
request.threadId);
return Flux.error(
new ResponseStatusException(HttpStatus.BAD_REQUEST, "appName cannot be null or empty"));
}
if (request.threadId == null || request.threadId.trim().isEmpty()) {
log.warn(
"threadId cannot be null or empty in SSE request for appName: {}, session: {}",
request.appName,
request.threadId);
return Flux.error(
new ResponseStatusException(HttpStatus.BAD_REQUEST, "threadId cannot be null or empty"));
}
try {
Agent agent = agentLoader.loadAgent(request.appName);
RunnableConfig runnableConfig = RunnableConfig.builder()
.threadId(request.threadId)
.addMetadata("user_id", request.userId)
.build();
return executeAgent(request.newMessage.toUserMessage(), agent, runnableConfig);
}
catch (Exception e) {
log.error("Error during agent run for session {}", request.threadId, e);
return Flux.error(new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Agent run failed", e));
}
}
@PostMapping(value = "/resume_sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)View on GitHub (pinned to f82da0b50f)
Solutions
- Set a non-empty threadId in the AgentRunRequest body before calling the endpoint
- Generate a threadId client-side (e.g. UUID) when starting a new conversation
- Validate the request payload on the client before opening the SSE connection
Example fix
// before
POST /run_sse {"appName":"chatbot"}
// after
POST /run_sse {"appName":"chatbot","threadId":"a1b2c3"} Defensive patterns
Strategy: validation
Validate before calling
if (req.threadId == null || req.threadId.trim().isEmpty()) { throw new IllegalArgumentException("threadId required"); } Type guard
boolean hasThreadId(AgentRunRequest r) { return r != null && r.threadId() != null && !r.threadId().trim().isEmpty(); } Try / catch
try { flux.subscribe(...) } catch (ResponseStatusException e) { if (e.getStatusCode() == HttpStatus.BAD_REQUEST) { /* fix request fields */ } } Prevention
- Always set threadId before calling /run_sse
- Generate a UUID threadId per conversation on the client
- Validate required request fields before opening SSE streams
When it happens
Trigger: POSTing to /execution/run_sse with a JSON body whose threadId field is absent, null, or whitespace-only.
Common situations: Client SDKs omitting threadId when starting a run; frontend state not yet initialized before opening the SSE stream; serialized request objects dropping empty strings; API version changes renaming the field.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/3c07a0d701d66c77.
Report an issue: GitHub.