windmill-labs/windmill · error

Backend runnable '${target.key}' not found.

Error message

Backend runnable '${target.key}' not found.

What it means

When the patch path targets a backend runnable (backend/<key>/main.ts|py), applyPatch looks the runnable up by key via helpers.getBackendRunnable. This error is thrown when no runnable with that key exists in the app's frontend definition. It catches references to deleted, renamed, or never-existing backend runnables.

Source

Thrown at frontend/src/lib/components/copilot/chat/app/core.ts:621

			let currentContent = ''
			let backendRunnable: BackendRunnable | undefined

			if (target.type === 'frontend') {
				if (target.path === '/wmill.d.ts') {
					throw new Error(
						"'/wmill.d.ts' is generated automatically. Edit backend runnables instead."
					)
				}

				const frontendContent = helpers.getFrontendFile(target.path)
				if (frontendContent === undefined) {
					throw new Error(`Frontend file '${target.path}' not found.`)
				}
				currentContent = frontendContent
			} else {
				backendRunnable = helpers.getBackendRunnable(target.key)
				if (!backendRunnable) {
					throw new Error(`Backend runnable '${target.key}' not found.`)
				}
				if (backendRunnable.type !== 'inline' || !backendRunnable.inlineScript) {
					throw new Error(
						`'${target.path}' points to backend runnable '${target.key}', but only inline runnables can be patched as files.`
					)
				}

				const expectedExtension = getBackendInlineScriptExtension(backendRunnable)
				if (target.extension !== expectedExtension) {
					throw new Error(
						`'${target.path}' does not match runnable '${target.key}' language. Use backend/${target.key}/main.${expectedExtension}.`
					)
				}

				currentContent = backendRunnable.inlineScript.content ?? ''
			}

			const updatedContent = findAndReplace(

View on GitHub (pinned to e474e8803c)

Solutions

  1. List the app's backend runnables first and patch an existing key
  2. Re-create the runnable (via the add-runnable tool) before patching its file
  3. Verify the key segment between backend/ and /main — it must exactly equal the runnable id in the app definition
Defensive patterns

Strategy: validation

Validate before calling

const runnable = helpers.getBackendRunnable(key)
if (!runnable) throw new Error(`No backend runnable named ${key}`)

Type guard

function backendRunnableExists(key: string, helpers: AppHelpers): boolean {
  return helpers.getBackendRunnable(key) !== undefined
}

Try / catch

try {
  await patchTool({ path: `backend/${key}/main.ts`, ... })
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Backend runnable')) {
    toolCallbacks.report(`Runnable '${key}' does not exist; list runnables first`)
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Patching 'backend/my_step/main.ts' when the app's runnables map has no 'my_step' key — the runnable was renamed, removed by a previous patch, or the model invented the key.

Common situations: Model guessing runnable names instead of listing them; earlier diff removed the runnable; key casing/spelling mismatch; editing a flow-generated app where steps use different ids.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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