windmill-labs/windmill · error

Resource at path ${path} already exists. Delete it or pick a

Error message

Resource at path ${path} already exists. Delete it or pick another path

What it means

In `next` (AppConnectInner.svelte), when the connect dialog is not in 'filling' mode (i.e. it is creating/importing fresh rather than filling an existing resource) and the chosen path already exists, Windmill refuses to proceed to avoid silently overwriting an existing resource.

Source

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

					occupantType = (
						await ResourceService.getResource({ workspace: effectiveWorkspace, path })
					)?.resource_type
				} catch (e: any) {
					throw Error(
						`Could not read what is already at ${path} (${e?.body ?? e?.message ?? e}), ` +
							`so it will not be written over. Try again.`
					)
				}
				if (occupantType !== resourceType) {
					throw Error(
						`Resource at path ${path} is ${
							occupantType ? `a ${occupantType} resource` : 'of an unknown type'
						}, not ${resourceType}. Move or rename it, then import again.`
					)
				}
			}
			if (exists && !filling) {
				throw Error(`Resource at path ${path} already exists. Delete it or pick another path`)
			}

			// Per-instance OAuth providers (Snowflake, ServiceNow, …): fill the
			// resource args from the connection's instance, per the registry
			// template's resource_mapping (e.g. ServiceNow -> instance_url:
			// https://{instance}.service-now.com). Bring-your-own carries the instance
			// the user entered in `ccInstance` (raw, possibly a full host); the shared
			// path carries it (already normalized) in the connect entry's extra_params.
			// Prefer the user-entered one so the saved resource matches the exchange.
			const connectTemplate = registryEntryFor(resourceType)?.connect_config_template
			if (connectTemplate?.resource_mapping) {
				const instanceKey = connectTemplate.extra_params_key ?? 'instance'
				let instanceValue = extra_params.find(([key, _]) => key === instanceKey)?.[1] ?? ''
				if (ccInstance.trim()) {
					const stripSuffix = connectTemplate.strip_suffix as string | undefined
					let v = ccInstance
						.trim()
						.replace(/^https?:\/\//, '')

View on GitHub (pinned to e474e8803c)

Solutions

  1. Delete the existing resource at that path if it is obsolete, then retry
  2. Choose a different path in the dialog
  3. Enter the edit/fill flow for the existing resource instead of import
  4. Use the resource edit UI to update credentials in place rather than re-importing

Example fix

// before: blind re-import to same path
await connectNext();
// after: clear stale resource or pick a fresh path
if (await resourceExists(workspace, path)) await ResourceService.deleteResource({ workspace, path });
await connectNext();
Defensive patterns

Strategy: validation

Validate before calling

const occupant = await ResourceService.getResource({ workspace, path }).catch(() => null);
if (occupant) throw new Error(`Path ${path} already exists — pick another or delete first`);

Try / catch

try { await connectNext(); } catch (e) {
  if (/already exists\. Delete it or pick another path/.test(String(e))) {
    path = suggestAlternativePath(path); // or delete stale resource
    await connectNext();
  } else throw e;
}

Prevention

When it happens

Trigger: Submitting the connect form with a path that resolves to an existing resource while the flow is in create/import mode rather than re-fill mode.

Common situations: Re-running the OAuth import after a previous successful save, a user re-typing a previously used path, or switching workspaces where a same-named resource already exists.

Related errors


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