windmill-labs/windmill · warning
The tool list for ${path} changed while it was loading. Try
Error message
The tool list for ${path} changed while it was loading. Try again. What it means
Thrown by loadServerTools in mcpTools.ts, used by the AI chat's global mode to fetch an MCP server's tool list with a generation-based cache. While the ResourceService.getMcpTools request is in flight, a cache invalidation (cacheGeneration bump via clearMcpToolsCache) makes the fetched list stale; the code loops/retries until the fetch lands in the current generation, and if the generation keeps changing it gives up with this error telling the caller to retry. It exists to prevent returning a tool list that no longer matches the server's current configuration.
Source
Thrown at frontend/src/lib/components/copilot/chat/global/mcpTools.ts:61
revision?: string
): Promise<McpToolDef[]> {
const key = `${workspace}:${path}:${revision ?? ''}`
const cached = toolsCache[key]
if (cached && Date.now() - cached.at < TOOLS_CACHE_TTL_MS) {
return cached.tools
}
// A clear while this is in flight means the path may now name a different
// server, and `readOnlyHint` decides whether a call needs confirmation — so the
// answer is thrown away and asked again rather than cached or returned.
for (let attempt = 0; attempt < 2; attempt++) {
const generation = cacheGeneration
const tools = await ResourceService.getMcpTools({ workspace, path })
if (generation === cacheGeneration) {
toolsCache[key] = { tools, at: Date.now() }
return tools
}
}
throw new Error(`The tool list for ${path} changed while it was loading. Try again.`)
}
export function clearMcpToolsCache() {
cacheGeneration++
toolsCache = {}
}
/**
* Drop one server's listing after the backend refused the read-only assertion it
* produced. Without this the write call the model is being sent to would be
* rejected by the same stale `readOnlyHint`, leaving it with nowhere to go until
* the entry expires.
*/
function forgetServerTools(workspace: string, path: string) {
cacheGeneration++
const prefix = `${workspace}:${path}:`
for (const key of Object.keys(toolsCache)) {
if (key.startsWith(prefix)) delete toolsCache[key]View on GitHub (pinned to e474e8803c)
Solutions
- Retry the operation — the error message says to try again once the MCP server configuration settles.
- Wait for any in-flight edit/reconnect of the MCP server to finish, then reload the chat tools.
- If it recurs constantly, find what is repeatedly calling clearMcpToolsCache (e.g. a reconnect loop) and fix that loop.
Example fix
// before
const tools = await loadServerTools(workspace, path) // throws while cache keeps invalidating
// after: retry with backoff
let tools
for (let i = 0; i < 3; i++) {
try { tools = await loadServerTools(workspace, path); break }
catch (e) { if (!/changed while it was loading/.test(e.message)) throw e; await sleep(500 * (i + 1)) }
} Defensive patterns
Strategy: retry
Validate before calling
import { clearMcpToolsCache } from '$lib/components/copilot/chat/global/mcpTools'
// don't clear the MCP tools cache while a load is in flight
clearMcpToolsCache()
await loadServerTools(workspace, path) Try / catch
try {
tools = await loadServerTools(workspace, path)
} catch (e) {
if (/changed while it was loading/.test(e.message)) {
await sleep(500)
tools = await loadServerTools(workspace, path) // retry after invalidations settle
} else throw e
} Prevention
- Avoid editing the MCP server resource while the chat is loading its tools.
- Serialize clearMcpToolsCache calls instead of firing them concurrently.
- Add retry-with-backoff around tool loading in agent loops.
When it happens
Trigger: Calling the MCP tool-loading path (e.g. the chat's tools() flow) while something repeatedly invalidates the cache — editing/reconfiguring the MCP server, rapid re-connections, or concurrent clearMcpToolsCache() calls — so generation !== cacheGeneration on every completed fetch.
Common situations: A user edits the MCP server resource in another tab while the chat is loading tools; an agent session reconnects the MCP server mid-load; multiple chat messages in parallel each triggering cache clears; flapping MCP server connections causing repeated invalidations.
Related errors
- Failed to cache esbuild-wasm@${version} at ${destDir}
- A connection already exists at ${resourcePath}. Pick another
- Variable at path ${path} already exists. Delete it or pick a
- A data table called ${name} was created while this setup was
- A variable was created at ${path} while this setup was runni
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/f6660e7d6e210c6f.
Report an issue: GitHub.