windmill-labs/windmill · error
Backend runnable "${key}" not found in app "${path}".
Error message
Backend runnable "${key}" not found in app "${path}". What it means
Thrown by the delete_app_runnable tool when the given `key` is not present in the app draft's `runnables` map, so there is nothing to remove. Note that unlike the lookup error (395), this one does not enumerate available runnables.
Source
Thrown at frontend/src/lib/components/copilot/chat/global/core.ts:6065
background: args.background,
detachAfterMs: waitSecondsToDetachMs(args.wait_seconds),
label: `${path} / ${key}`
})
}
async function deleteAppRunnable(
args: { path: string; key: string },
ctx: WriteDraftCtx
): Promise<string> {
const { workspace, toolId, toolCallbacks } = ctx
const { path, key } = args
toolCallbacks.setToolStatus(toolId, {
content: `Removing runnable "${key}" from app "${path}"...`
})
const { value } = await loadAppDraftValue(path, workspace)
if (!(key in value.runnables)) {
throw new Error(`Backend runnable "${key}" not found in app "${path}".`)
}
const { [key]: _removed, ...remaining } = value.runnables
value.runnables = remaining
await recomputeAppPolicy(value)
const result = await saveAppDraft(workspace, path, value)
return finishAppDraftWrite(result, ctx, () => ({
content: `Removed runnable "${key}" from app "${path}"`,
message: `Removed runnable "${key}" from draft app "${path}".`
}))
}
const triggerLabels: Record<TriggerKind, string> = {
http: 'HTTP trigger',
websocket: 'WebSocket trigger',
kafka: 'Kafka trigger',
nats: 'NATS trigger',
postgres: 'Postgres trigger',
mqtt: 'MQTT trigger',View on GitHub (pinned to e474e8803c)
Solutions
- Re-read the app draft to list existing runnables and retry with a valid key
- If already deleted, treat the removal as done and move on
- Rebase/reset the draft if you expected the runnable to be present from the deployed version
Example fix
// before
delete_app_runnable({ path: 'f/app_main', key: 'old_job' }) // not in draft
// after
// verify with a read of the app draft, then target an existing key:
delete_app_runnable({ path: 'f/app_main', key: 'oldJob' }) Defensive patterns
Strategy: validation
Validate before calling
const { value } = await loadAppDraftValue(path, workspace)
if (!(key in (value.runnables ?? {}))) {
return // already gone; no-op
} Type guard
function runnableExists(runnables: Record<string, unknown> | undefined, key: string): boolean {
return !!runnables && key in runnables
} Try / catch
try {
await deleteAppRunnable(args)
} catch (e) {
if (e instanceof Error && e.message.includes('not found in app')) {
// treat as already deleted; skip instead of retrying
}
} Prevention
- Make deletes idempotent in agent loops: check existence first
- Track deletions within the session to avoid double-delete
- Verify the key exists in the draft (not just the deployed version)
When it happens
Trigger: delete_app_runnable is called with a key absent from `value.runnables` — already deleted, typo, or key that only exists in the deployed (not draft) version.
Common situations: Double-delete after a previous successful removal in the same session; model hallucinating a runnable name; draft was reset/rebased so the runnable no longer exists in it.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- App "${path}" has no backend runnable "${key}". Available ru
- write_app_file only writes frontend files. Use write_app_run
- delete_app_file only deletes frontend files. Use delete_app_
- Frontend file "${target.filePath}" not found in app "${path}
- No draft found for ${type} "${path}".
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/a4bb444ae2893b2d.
Report an issue: GitHub.