alibaba/arthas · error · McpError
-32602
-32602
Error message
Task not found (may have expired after TTL): {} What it means
Thrown by InMemoryTaskStore during result storage (the storeResult/update path) when the target taskId is not present in the tasks map (taskFound.get() is false after the compute-if-present block). It builds a McpError with ErrorCodes.INVALID_PARAMS (-32602). The message notes the task may have expired after its TTL, distinguishing a 'never existed or evicted' case from a session-mismatch case.
Source
Thrown at arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/task/InMemoryTaskStore.java:275
wasTerminal.set(true);
return entry;
}
results.put(taskId, result);
String now = Instant.now().toString();
McpSchema.Task newTask = McpSchema.Task.builder()
.taskId(oldTask.getTaskId())
.status(status)
.createdAt(oldTask.getCreatedAt())
.lastUpdatedAt(now)
.ttl(oldTask.getTtl())
.pollInterval(oldTask.getPollInterval())
.build();
logger.debug("Stored result for task: {}", taskId);
return new TaskEntry(newTask, entry.originatingRequest(), entry.context(), entry.sessionId());
});
if (!taskFound.get()) {
throw new CompletionException(
McpError.builder(McpSchema.ErrorCodes.INVALID_PARAMS)
.message("Task not found (may have expired after TTL): " + taskId)
.build()
);
}
if (!sessionValid.get()) {
throw new CompletionException(
McpError.builder(McpSchema.ErrorCodes.INVALID_PARAMS)
.message("Task not found (may have expired after TTL): " + taskId)
.build()
);
}
if (wasTerminal.get()) {
logger.debug("Skipped storing result for task {} - already in terminal state", taskId);
}
});
}
View on GitHub (pinned to 21cf2e9ba5)
Solutions
- Ensure task completion stores results well within the configured TTL window.
- Increase the task TTL to exceed the handler's realistic completion time.
- Confirm the result is stored against the same TaskStore instance and taskId used at creation.
- For durability across restarts, use a persistent TaskStore instead of the in-memory one.
Example fix
// before Long ttl = Duration.ofSeconds(10).toMillis(); // shorter than task runtime store.createTask(opts.withRequestedTtl(ttl)); // ... later, after expiry store.storeResult(taskId, result); // INVALID_PARAMS // after Long ttl = Duration.ofMinutes(10).toMillis(); // exceeds runtime store.createTask(opts.withRequestedTtl(ttl)); store.storeResult(taskId, result); // ok
Defensive patterns
Strategy: validation
Validate before calling
// Ensure TTL exceeds the handler's realistic completion time long ttl = Math.max(defaultTtl, estimatedMaxRuntimeMillis * 3); options = options.withRequestedTtl(ttl); store.createTask(options);
Try / catch
try {
store.storeResult(taskId, result).join();
} catch (CompletionException e) {
Throwable c = e.getCause();
if (c instanceof McpError me && me.getMessage().contains("expired after TTL")) {
// task was evicted; recreate or report stale, do not loop
logger.warn("Task {} expired before result stored", taskId);
return;
}
throw e;
} Prevention
- Store results well within the TTL window.
- Set TTL larger than the handler's worst case.
- Confirm you use the same store instance and taskId.
- Use a persistent store if the process may restart mid-task.
When it happens
Trigger: A task handler tries to store a result for a taskId that was evicted by TTL before completion, or for a taskId that was never created in this store; late result delivery after expiry.
Common situations: Long-running task whose result arrives after TTL eviction; result posted to the wrong store instance; store restart losing in-memory state; handler holding a stale taskId.
Related errors
AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14).
Data as JSON: /api/errors/b07d7bf57bbc029a.
Report an issue: GitHub.