{"record":{"id":"a4bb444ae2893b2d","repo":"windmill-labs/windmill","slug":"backend-runnable-key-not-found-in-app-path","errorCode":null,"errorMessage":"Backend runnable \"${key}\" not found in app \"${path}\".","messagePattern":"Backend runnable \"(.+?)\" not found in app \"(.+?)\"\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/global/core.ts","lineNumber":6065,"sourceCode":"\t\tbackground: args.background,\n\t\tdetachAfterMs: waitSecondsToDetachMs(args.wait_seconds),\n\t\tlabel: `${path} / ${key}`\n\t})\n}\n\nasync function deleteAppRunnable(\n\targs: { path: string; key: string },\n\tctx: WriteDraftCtx\n): Promise<string> {\n\tconst { workspace, toolId, toolCallbacks } = ctx\n\tconst { path, key } = args\n\ttoolCallbacks.setToolStatus(toolId, {\n\t\tcontent: `Removing runnable \"${key}\" from app \"${path}\"...`\n\t})\n\n\tconst { value } = await loadAppDraftValue(path, workspace)\n\tif (!(key in value.runnables)) {\n\t\tthrow new Error(`Backend runnable \"${key}\" not found in app \"${path}\".`)\n\t}\n\tconst { [key]: _removed, ...remaining } = value.runnables\n\tvalue.runnables = remaining\n\tawait recomputeAppPolicy(value)\n\tconst result = await saveAppDraft(workspace, path, value)\n\treturn finishAppDraftWrite(result, ctx, () => ({\n\t\tcontent: `Removed runnable \"${key}\" from app \"${path}\"`,\n\t\tmessage: `Removed runnable \"${key}\" from draft app \"${path}\".`\n\t}))\n}\n\nconst triggerLabels: Record<TriggerKind, string> = {\n\thttp: 'HTTP trigger',\n\twebsocket: 'WebSocket trigger',\n\tkafka: 'Kafka trigger',\n\tnats: 'NATS trigger',\n\tpostgres: 'Postgres trigger',\n\tmqtt: 'MQTT trigger',","sourceCodeStart":6047,"sourceCodeEnd":6083,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/global/core.ts#L6047-L6083","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ndelete_app_runnable({ path: 'f/app_main', key: 'old_job' }) // not in draft\n// after\n// verify with a read of the app draft, then target an existing key:\ndelete_app_runnable({ path: 'f/app_main', key: 'oldJob' })","handlingStrategy":"validation","validationCode":"const { value } = await loadAppDraftValue(path, workspace)\nif (!(key in (value.runnables ?? {}))) {\n  return // already gone; no-op\n}","typeGuard":"function runnableExists(runnables: Record<string, unknown> | undefined, key: string): boolean {\n  return !!runnables && key in runnables\n}","tryCatchPattern":"try {\n  await deleteAppRunnable(args)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('not found in app')) {\n    // treat as already deleted; skip instead of retrying\n  }\n}","preventionTips":["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)"],"tags":["ai-agent","not-found","app-editing"],"backgroundTag":"resource-not-found","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"}