windmill-labs/windmill · error · Error

An app already exists at "${path}". Use read_workspace_item

Error message

An app already exists at "${path}". Use read_workspace_item + write_app_file / write_app_runnable to modify it.

What it means

Beyond draft conflicts, write_app also refuses when a deployed app already exists at the given path. Creating would overwrite an existing app, so the tool throws and directs the caller to read the existing app and modify it with write_app_file / write_app_runnable rather than recreating it from a template.

Source

Thrown at frontend/src/lib/components/copilot/chat/global/core.ts:5499

async function initApp(
	args: {
		path: string
		summary?: string
		framework: FrameworkKey
	},
	ctx: WriteDraftCtx
): Promise<string> {
	const { workspace, toolId, toolCallbacks } = ctx
	const { path, summary, framework } = args

	if (await getGlobalDraft(workspace, 'app', path)) {
		throw new Error(
			`A draft for app "${path}" already exists. Use write_app_file / write_app_runnable to modify it, or delete the existing draft first.`
		)
	}
	if (await AppService.existsApp({ workspace, path })) {
		throw new Error(
			`An app already exists at "${path}". Use read_workspace_item + write_app_file / write_app_runnable to modify it.`
		)
	}

	toolCallbacks.setToolStatus(toolId, {
		content: `Saving app "${path}" draft (${framework} template)…`
	})

	const template = FRAMEWORK_TEMPLATES[framework]
	const value: AppDraftValue = {
		summary,
		files: { ...template },
		runnables: { [STARTER_RUNNABLE_KEY]: { ...STARTER_RUNNABLE } }
	}
	await recomputeAppPolicy(value)
	const result = await saveAppDraft(workspace, path, value)
	return finishAppDraftWrite(result, ctx, () => ({
		content: `Saved app "${path}" draft (${framework})`,

View on GitHub (pinned to e474e8803c)

Solutions

  1. Pick a new, unused app path for the write_app call.
  2. Call read_workspace_item on the existing app and modify it via write_app_file / write_app_runnable.
  3. Delete or rename the existing app if it should be replaced, then re-run write_app.

Example fix

// before
writeApp({ path: 'f/existing_app', framework: 'svelte' }) // already deployed
// after
writeApp({ path: 'f/existing_app_v2', framework: 'svelte' })
// or: read_workspace_item('app', 'f/existing_app') then writeAppFile(...)
Defensive patterns

Strategy: validation

Validate before calling

if (await AppService.existsApp({ workspace, path })) {
  // path taken: read existing app and modify, or choose a new path
}

Try / catch

try {
  await writeApp(args)
} catch (e) {
  if (e.message.startsWith('An app already exists at')) {
    const existing = await readWorkspaceItem('app', args.path)
    // modify via write_app_file/write_app_runnable or pick a new path
  } else throw e
}

Prevention

When it happens

Trigger: Calling the write_app tool when AppService.existsApp({ workspace, path }) is true and no draft exists — i.e. the target path already has a deployed app.

Common situations: Scaffolding an app at a path that already hosts a production app; reusing an old app path for a new generated app; the model guessed a path without checking existence.

Related errors


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