alibaba/spring-ai-alibaba · error · IllegalArgumentException
threadId is not allow null
Error message
threadId is not allow null
What it means
RedisSaver.list(CheckpointSaver.RunnableConfig) requires the config to carry a threadId, since checkpoints are keyed by thread in Redis. If Optional<String> threadId() is empty it throws this IllegalArgumentException before touching Redis.
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/redis/RedisSaver.java:227
private String getActiveThreadId(String threadName) {
String metaKey = THREAD_META_PREFIX + threadName;
RMap<String, String> meta = redisson.getMap(metaKey);
String threadId = meta.get(FIELD_THREAD_ID);
String isReleased = meta.get(FIELD_IS_RELEASED);
if (threadId != null && !"true".equals(isReleased)) {
return threadId;
}
return null; // No active thread exists
}
@Override
public Collection<Checkpoint> list(RunnableConfig config) {
Optional<String> threadNameOpt = config.threadId();
if (!threadNameOpt.isPresent()) {
throw new IllegalArgumentException("threadId is not allow null");
}
String threadName = threadNameOpt.get();
RLock lock = redisson.getLock(LOCK_PREFIX + threadName);
boolean tryLock = false;
try {
// 500ms timeout for read operations (list)
tryLock = lock.tryLock(500, TimeUnit.MILLISECONDS);
if (!tryLock) {
return List.of();
}
// Get active thread_id for the thread_name
String threadId = getActiveThreadId(threadName);
if (threadId == null) {
return List.of();
}
View on GitHub (pinned to f82da0b50f)
Solutions
- Build the config with a threadId: RunnableConfig.builder().threadId("my-thread").build().
- Check config.threadId().isPresent() before calling list() and fall back to a default thread id.
- Trace where the RunnableConfig originates and ensure threadId is set at graph/stream invocation time.
Example fix
// before saver.list(RunnableConfig.builder().build()); // after saver.list(RunnableConfig.builder().threadId(threadId).build());
Defensive patterns
Strategy: validation
Validate before calling
if (config == null || config.threadId().isEmpty()) {
throw new IllegalStateException("RunnableConfig must carry a threadId before list()");
} Try / catch
try { saver.list(config); } catch (IllegalArgumentException e) { if (e.getMessage().contains("threadId")) { config = RunnableConfig.builder().threadId(defaultId).build(); saver.list(config); } else throw e; } Prevention
- Always set threadId in RunnableConfig builders
- Centralize RunnableConfig creation in one factory
- Validate config before checkpoint API calls
When it happens
Trigger: Calling saver.list(RunnableConfig.builder().build()) or building a RunnableConfig without .threadId("...").
Common situations: Constructing RunnableConfig programmatically and forgetting the threadId; propagating a config from a graph run that never had an explicit thread id; refactored code where threadId assignment was dropped.
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 isn't 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/ee68b07004da457b.
Report an issue: GitHub.