alibaba/spring-ai-alibaba · error · IllegalArgumentException
threadId isn't allow null
Error message
threadId isn't allow null
What it means
RedisSaver.get(CheckpointSaver.RunnableConfig) requires a threadId in the config; if Optional<String> threadId() is empty it throws IllegalArgumentException('threadId isn\u2019t allow null') before acquiring the Redis lock. (This method backs checkpoint(...) and retrieved(...) flows.)
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/redis/RedisSaver.java:267
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Failed to deserialize checkpoints", e);
}
finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
@Override
public Optional<Checkpoint> get(RunnableConfig config) {
Optional<String> threadNameOpt = config.threadId();
if (!threadNameOpt.isPresent()) {
throw new IllegalArgumentException("threadId isn't allow null");
}
String threadName = threadNameOpt.get();
RLock lock = redisson.getLock(LOCK_PREFIX + threadName);
boolean tryLock = false;
try {
// 500ms timeout for read operations (get)
tryLock = lock.tryLock(500, TimeUnit.MILLISECONDS);
if (!tryLock) {
return Optional.empty();
}
// Get active thread_id for the thread_name
String threadId = getActiveThreadId(threadName);
if (threadId == null) {
return Optional.empty();
}
View on GitHub (pinned to f82da0b50f)
Solutions
- Always set threadId when building RunnableConfig for checkpoint operations.
- Guard calls: if (config.threadId().isEmpty()) throw/skip before invoking get().
- Ensure your stateful runnable assigns a threadId at start (e.g. via RunnableConfig with a stable session id).
Example fix
// before Optional<Checkpoint> cp = saver.get(RunnableConfig.builder().build()); // after RunnableConfig config = RunnableConfig.builder().threadId(sessionId).build(); Optional<Checkpoint> cp = saver.get(config);
Defensive patterns
Strategy: validation
Validate before calling
if (config == null || config.threadId().isEmpty()) {
throw new IllegalStateException("RunnableConfig must carry a threadId before get()");
} Try / catch
try { saver.get(config); } catch (IllegalArgumentException e) { if (e.getMessage().contains("threadId")) throw new IllegalStateException("Set threadId on RunnableConfig", e); throw e; } Prevention
- Generate a stable threadId (session id) per conversation
- Centralize RunnableConfig construction
- Assert threadId presence before any checkpoint API call
When it happens
Trigger: Calling saver.get(config) or code paths like checkpoint()/retrieved() with a RunnableConfig built without threadId — e.g. RunnableConfig.builder().build().
Common situations: Forgetting threadId when resuming a graph from a checkpoint; configs copied from a fresh invocation that never got an id; tests constructing minimal configs.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- threadId is not allow null
- Failed to deserialize checkpoints
- Failed to serialize/deserialize checkpoints
- Thread not found:
- oss object name is invalid
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/9500cbb07eee21e4.
Report an issue: GitHub.