windmill-labs/windmill · error

Resource at path already exists. Delete it or pick another…

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.

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.

Appendix: 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)