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.)

Solutions

  1. Always set threadId when building RunnableConfig for checkpoint operations.
  2. Guard calls: if (config.threadId().isEmpty()) throw/skip before invoking get().
  3. 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

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


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

Appendix: 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)