windmill-labs/windmill · error
Variable at path ${path} already exists. Delete it or pick a
Error message
Variable at path ${path} already exists. Delete it or pick another path. What it means
The MCP secret-variable store keeps a variable at `path`; if it exists with a different description than the one being saved, the code cannot tell whether it is the same connection's variable and throws rather than overwriting unrelated data. Same description means it is the same connection and the save proceeds (update/rotate).
Source
Thrown at frontend/src/lib/components/mcp/secretVariable.ts:52
resourcePath: string
isOauth?: boolean
account?: number
}): Promise<void> {
const { workspace, path, value, resourcePath, isOauth, account } = args
const description = mcpTokenDescription(resourcePath)
// The path picker rejects an occupied path, but it validates on a debounce and
// this runs on the click: without the check, a fast save would rotate the token
// of the connection already living there and only then fail to create its
// resource, leaving that server holding a credential meant for another one.
if (await ResourceService.existsResource({ workspace, path: resourcePath })) {
throw new Error(`A connection already exists at ${resourcePath}. Pick another path.`)
}
if (await VariableService.existsVariable({ workspace, path })) {
const current = await VariableService.getVariable({ workspace, path, decryptSecret: false })
if (current.description !== description) {
throw new Error(`Variable at path ${path} already exists. Delete it or pick another path.`)
}
if (!isOauth) {
// `is_secret` is inherited from the row when omitted, so it is restated
// rather than assumed.
await VariableService.updateVariable({
workspace,
path,
requestBody: { value, is_secret: true }
})
return
}
await VariableService.deleteVariable({ workspace, path })
}
await VariableService.createVariable({
workspace,
requestBody: { path, value, is_secret: true, is_oauth: isOauth, account, description }
})View on GitHub (pinned to e474e8803c)
Solutions
- Choose a new variable `path` for this connection.
- Or delete the existing variable (and its connection) if it is obsolete, then save.
- If it IS the same connection, ensure the description matches the existing one so the upsert path continues.
- List variables in the workspace to identify the occupier before saving.
Example fix
// before
await upsertSecretVariable({ workspace, path: 'mcp_secret', description: 'conn A', ... })
// after
await upsertSecretVariable({ workspace, path: 'mcp_secret_conn_a', description: 'conn A', ... }) Defensive patterns
Strategy: validation
Validate before calling
const exists = await VariableService.existsVariable({ workspace, path })
if (exists) {
const cur = await VariableService.getVariable({ workspace, path, decryptSecret: false })
if (cur.description !== description) alert('Variable path belongs to another connection')
} Try / catch
try { await upsertSecretVariable(args) } catch (e) { if (String(e.message).includes('Variable at path')) promptNewVariablePath(); else throw e } Prevention
- Derive variable paths from the connection name so description and path stay consistent
- Never reuse a variable path across connections
- List existing variables before choosing a path for a new connection
When it happens
Trigger: Saving a connection whose variable path collides with an existing variable that has a different description — i.e. the path belongs to a different connection.
Common situations: Renaming a connection without changing its description; reusing a variable path chosen earlier for another integration; imported config pointing at an existing variable path.
Related errors
- A connection already exists at ${resourcePath}. Pick another
- The tool list for ${path} changed while it was loading. Try
- duplicate MCP tool name(s): {', '.join(duplicates)}
- MCP server does not publish OAuth authorization metadata
- MCP server URL is not allowed: {}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/c9cdfd55ca4a39d9.
Report an issue: GitHub.