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

During the app OAuth connect flow, before creating the credential variable the frontend calls `VariableService.existsVariable` for the chosen path. If a variable already exists there, it throws "Variable at path <path> already exists. Delete it or pick another path". Windmill variable paths are unique per workspace, so a collision blocks writing new OAuth credentials.

Source

Thrown at frontend/src/lib/components/AppConnectInner.svelte:734

				window.addEventListener('message', popupListener)
				window.addEventListener('storage', handleStorageEvent)
				console.log('opening popup', url.toString())
				window.open(url.toString(), '_blank', 'popup=true')
				step += 1
			}
		} else {
			if (!path) {
				if (step == 2) return
				throw Error('Path is not set')
			}
			// Check if variable paths already exist
			if (!manual || linkedSecrets.length <= 1) {
				const exists = await VariableService.existsVariable({
					workspace: effectiveWorkspace,
					path
				})
				if (exists) {
					throw Error(`Variable at path ${path} already exists. Delete it or pick another path`)
				}
			} else {
				for (const secretField of linkedSecrets) {
					const varPath = `${path}_${secretField}`
					const exists = await VariableService.existsVariable({
						workspace: effectiveWorkspace,
						path: varPath
					})
					if (exists) {
						throw Error(
							`Variable at path ${varPath} already exists. Delete it or pick another path`
						)
					}
				}
			}
			let exists = await ResourceService.existsResource({
				workspace: effectiveWorkspace,
				path

View on GitHub (pinned to e474e8803c)

Solutions

  1. Pick a different, unique path in the connect dialog (e.g. suffix it with the app or environment name).
  2. Delete the existing variable at that path (Variables page in the workspace) if it is stale, then retry.
  3. If the existing variable holds the credentials you want, skip re-creation and link the resource to the existing variable instead.
  4. Check the workspace in `effectiveWorkspace` — the collision may exist in the wrong workspace context.

Example fix

// before: path collides with an existing variable
path = 'hubspot_credentials';
await next();

// after: ensure a unique path up front
path = 'hubspot_credentials';
if (await VariableService.existsVariable({ workspace, path })) {
  path = 'hubspot_credentials_v2';
}
await next();
Defensive patterns

Strategy: validation

Validate before calling

// before starting the connect flow
if (await VariableService.existsVariable({ workspace, path })) {
  // pick another path or plan to reuse/delete the existing variable
  path = `${path}_${Date.now()}`;
}

Try / catch

try {
  await next();
} catch (e) {
  if (e instanceof Error && /already exists/.test(e.message)) {
    const p = e.message.match(/path (\S+) already/)?.[1];
    // offer rename or delete UI for the conflicting variable
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `next()` (from connectOauth/selectFromOthers/open/processPopupData/next) with `manual == true` having a single linkedSecret (or `linkedSecrets.length <= 1`), where `VariableService.existsVariable({workspace, path})` returns true.

Common situations: Re-running the connect wizard for an app whose credentials variable was created in a previous attempt; two apps configured with the same path; a stale variable left behind after a deleted resource.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/0bcd63e8873ce640. Report an issue: GitHub.