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
- Pick a new, unused app path for the write_app call.
- Call read_workspace_item on the existing app and modify it via write_app_file / write_app_runnable.
- 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
- Check existence (read_workspace_item / existsApp) before creating an app.
- Generate unique paths (suffix -v2, timestamp) when scaffolding new apps.
- Never assume a path is free — deployed apps block write_app.
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
- inlineScript is required when runnable type is "inline".
- path is required when runnable type is "script", "flow", or
- A draft for app "${path}" already exists. Use write_app_file
- Frontend file "${target.filePath}" not found in app "${args.
- Error occurred for HTTP route at route path: {}, error: {}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/90b5676d2a2ca328.
Report an issue: GitHub.