{"record":{"id":"5270064d4531b8b4","repo":"windmill-labs/windmill","slug":"variable-at-path-varpath-already-exists-delete","errorCode":null,"errorMessage":"Variable at path ${varPath} already exists. Delete it or pick another path","messagePattern":"Variable at path (.+?) already exists\\. Delete it or pick another path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/AppConnectInner.svelte","lineNumber":744,"sourceCode":"\t\t\t}\n\t\t\t// Check if variable paths already exist\n\t\t\tif (!manual || linkedSecrets.length <= 1) {\n\t\t\t\tconst exists = await VariableService.existsVariable({\n\t\t\t\t\tworkspace: effectiveWorkspace,\n\t\t\t\t\tpath\n\t\t\t\t})\n\t\t\t\tif (exists) {\n\t\t\t\t\tthrow Error(`Variable at path ${path} already exists. Delete it or pick another path`)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const secretField of linkedSecrets) {\n\t\t\t\t\tconst varPath = `${path}_${secretField}`\n\t\t\t\t\tconst exists = await VariableService.existsVariable({\n\t\t\t\t\t\tworkspace: effectiveWorkspace,\n\t\t\t\t\t\tpath: varPath\n\t\t\t\t\t})\n\t\t\t\t\tif (exists) {\n\t\t\t\t\t\tthrow Error(\n\t\t\t\t\t\t\t`Variable at path ${varPath} already exists. Delete it or pick another path`\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet exists = await ResourceService.existsResource({\n\t\t\t\tworkspace: effectiveWorkspace,\n\t\t\t\tpath\n\t\t\t})\n\n\t\t\t// Filling one names its path up front; anything else reaching an occupied path got\n\t\t\t// there by the user typing it, which is the case worth refusing.\n\t\t\t//\n\t\t\t// The type is checked here and not only by the caller: `fillPath` says \"write into\n\t\t\t// this path\", and a path says nothing about what lives at it. A workspace resource\n\t\t\t// of another type sitting where the project wanted one of ours would otherwise have\n\t\t\t// its value replaced with credentials for a different provider, while keeping its\n\t\t\t// own type — destroying a working resource that has nothing to do with the import.","sourceCodeStart":726,"sourceCodeEnd":762,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/AppConnectInner.svelte#L726-L762","documentation":"When the OAuth flow handles multiple linked secret fields (e.g. client_id + client_secret stored as separate variables), it derives a per-field path `<path>_<secretField>` and checks each for an existing variable. If any derived per-field variable path is taken, it throws \"Variable at path <varPath> already exists. Delete it or pick another path\". Same uniqueness rule as the single-path case, applied per secret field.","triggerScenarios":"Calling `next()` when `manual == true` and `linkedSecrets.length > 1`: the loop over `linkedSecrets` builds `${path}_${secretField}` for each field and one of the `existsVariable` checks returns true.","commonSituations":"Partial completion of a previous multi-secret connect attempt (first variable created, second collided); base path chosen to collide with another app's suffixed variables; re-connecting an app where `<path>_client_secret` already exists from an earlier config.","solutions":["Change the base path in the dialog — all derived `<path>_<field>` variables must be free.","Delete the conflicting `<path>_<secretField>` variable(s) listed in the message if they are stale.","Reuse the existing variables by pointing the resource at them instead of re-running creation.","Pre-check all derived paths before starting the flow (see validationCode) and resolve collisions up front."],"exampleFix":"// before: 'acme_oauth_secret' already exists, blocking creation\npath = 'acme_oauth'; // derives acme_oauth_client_id / acme_oauth_client_secret\nawait next();\n\n// after: pre-check every derived path\nconst fields = ['client_id', 'client_secret'];\nfor (const f of fields) {\n  const p = `${path}_${f}`;\n  if (await VariableService.existsVariable({ workspace, path: p })) throw new Error(`pick another base path: ${p} taken`);\n}\nawait next();","handlingStrategy":"validation","validationCode":"// check every derived per-field path before running the flow\nfor (const field of linkedSecrets) {\n  const varPath = `${path}_${field}`;\n  if (await VariableService.existsVariable({ workspace, path: varPath })) {\n    throw new Error(`base path '${path}' collides via ${varPath}; pick another`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await next();\n} catch (e) {\n  if (e instanceof Error && /already exists/.test(e.message)) {\n    const varPath = e.message.match(/path (\\S+) already/)?.[1];\n    // delete or rename that specific <base>_<field> variable, then retry\n  } else throw e;\n}","preventionTips":["Pre-check all `<base>_<secretField>` paths for every linked secret before advancing.","Choose base paths unlikely to collide (include app + environment in the name).","Remove leftover variables from partially completed connect attempts.","Reuse existing per-field variables instead of re-creating when reconnecting an app."],"tags":["windmill","svelte","frontend","oauth","variable","duplicate-path","linked-secrets"],"backgroundTag":"variable-path-already-exists","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}