windmill-labs/windmill · error · Error

item already exists in the target workspace

Error message

item already exists in the target workspace

What it means

Thrown during a Windmill workspace deploy when the item (flow, script, app, or variable) being deployed already exists at that path in the target workspace and the deploy was invoked in a mode that refuses to overwrite existing items. The provider wraps exists* checks and, when a conflict is detected, sets a conflict flag and refuses the update.

Source

Thrown at frontend/src/lib/utils_workspace_deploy.ts:210

function makeProvider(
	onBehalfOfPrincipal?: string,
	appIdentity?: AppIdentity,
	/**
	 * Refuse the writes the shared `deployItem` reaches for only when the item already exists in
	 * the target, turning its silent switch to an update into a failure the caller can act on.
	 * The three below are exactly its `alreadyExists` branches: a flow and an app are replaced
	 * outright, and a script is given the target's head as `parent_hash`, which is what makes an
	 * otherwise identical `createScript` an update.
	 */
	conflict?: DeployConflict
): DeployProvider {
	const withPermissionedAs = <T extends Record<string, any>>(requestBody: T): T => ({
		...requestBody,
		on_behalf_of: onBehalfOfPrincipal
	})
	const refuseUpdate = (): never => {
		if (conflict) conflict.hit = true
		throw new Error('item already exists in the target workspace')
	}
	return {
		existsFlowByPath: (p) => FlowService.existsFlowByPath(p),
		existsScriptByPath: (p) => ScriptService.existsScriptByPath(p),
		existsApp: (p) => AppService.existsApp(p),
		existsVariable: (p) => VariableService.existsVariable(p),
		existsResource: (p) => ResourceService.existsResource(p),
		existsResourceType: (p) => ResourceService.existsResourceType(p),
		existsFolder: (p) => FolderService.existsFolder(p),
		getFlowByPath: (p) => FlowService.getFlowByPath(p),
		createFlow: (p) =>
			FlowService.createFlow({ ...p, requestBody: withPermissionedAs(p.requestBody) }),
		updateFlow: (p) =>
			conflict
				? refuseUpdate()
				: FlowService.updateFlow({ ...p, requestBody: withPermissionedAs(p.requestBody) }),
		archiveFlowByPath: (p) => FlowService.archiveFlowByPath(p),
		getScriptByPath: (p) => ScriptService.getScriptByPath(p),

View on GitHub (pinned to e474e8803c)

Solutions

  1. Enable the deploy option that allows overwriting/syncing existing items (the caller decides via the conflict flag) instead of refusing updates
  2. Use a different path for the new item
  3. Delete or rename the existing item at that path in the target workspace before redeploying
  4. Inspect the conflict flag in makeProvider's returned object to identify which path collided

Example fix

// before
await deployWorkspace({ workspaces: ['target'], overwrite: false })
// after
await deployWorkspace({ workspaces: ['target'], overwrite: true })
Defensive patterns

Strategy: validation

Validate before calling

const exists = await FlowService.existsFlowByPath({ workspace, path });
if (exists && !allowOverwrite) {
  throw new Error(`Path already exists in target workspace: ${path}`)
}

Try / catch

try {
  await deployItem(item)
} catch (e) {
  if (e.message === 'item already exists in the target workspace') {
    // redeploy with overwrite enabled or skip this path
  } else throw e
}

Prevention

When it happens

Trigger: Deploying via utils_workspace_deploy.ts while the target path already holds an item of the same kind in the destination workspace, and the deploy options disallow overwriting (conflict policy).

Common situations: Re-running a deploy without a 'sync'/'overwrite' option; deploying to a workspace that already received an earlier deploy of the same paths; path collisions between two items that were renamed upstream.

Related errors


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