windmill-labs/windmill · error
Frontend file '${target.path}' not found.
Error message
Frontend file '${target.path}' not found. What it means
The applyPatch tool in the app-edit copilot resolves the given path to a frontend file and fetches its current content via helpers.getFrontendFile. When the path is not a backend runnable path and no frontend file exists at that path, this error is thrown. It signals a bad patch target: the file the model wants to edit does not exist in the app.
Source
Thrown at frontend/src/lib/components/copilot/chat/app/core.ts:615
showDetails: true,
showFade: true,
fn: async ({ args, helpers, toolId, toolCallbacks }) => {
const parsedArgs = getPatchFileSchema().parse(args)
const { old_string: oldString, new_string: newString, replace_all: replaceAll } = parsedArgs
const target = resolveAppPatchTarget(parsedArgs.path)
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}.`
)View on GitHub (pinned to e474e8803c)
Solutions
- Call the file-listing/read tool first to confirm the exact existing path, then patch that path
- Create the file with the create-file tool before patching it
- Check for extension mismatches (e.g. .tsx vs .ts) and leading-slash normalization — resolveAppPatchTarget adds '/' if missing
- If the file was intentionally new, use the creation path instead of patch
Example fix
// before
await applyPatch({ path: '/src/App.tsx', ... })
// after
const files = await listFiles()
await applyPatch({ path: files.find(f => f.endsWith('.tsx'))?.path, ... }) Defensive patterns
Strategy: validation
Validate before calling
const existing = helpers.getFrontendFile(normalizedPath)
if (existing === undefined) throw new Error(`Refusing to patch: no frontend file at ${normalizedPath}`) Type guard
function frontendFileExists(path: string, helpers: AppHelpers): boolean {
return helpers.getFrontendFile(path.startsWith('/') ? path : '/' + path) !== undefined
} Try / catch
try {
await patchTool({ path, ... })
} catch (e) {
if (e instanceof Error && /^Frontend file '.*' not found/.test(e.message)) {
await createFileTool({ path, content: '' }) // then retry patch
return
}
throw e
} Prevention
- List files (read tool) before patching; never patch from memory of an assumed path
- Create new files with the create tool, patch only existing ones
- Normalize leading slashes and check extension spelling (.tsx vs .ts)
When it happens
Trigger: Calling the patch tool with parsedArgs.path that maps to type 'frontend' (anything not matching /^backend\/([^/]+)\/main\.(ts|py)$/) while getFrontendFile returns undefined — path typos, wrong extension, or a file that was never created.
Common situations: Model hallucinating a file path ('/src/App.tsx' when the app uses '/index.tsx'); deleting a file in an earlier step then patching it; case-sensitive path mismatches; patching before creating the file.
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
- Backend runnable '${target.key}' not found.
- '/wmill.d.ts' is generated automatically. Edit backend runna
- '${target.path}' points to backend runnable '${target.key}',
- '${target.path}' does not match runnable '${target.key}' lan
- File not found: ${filePath}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/49835125bba8219e.
Report an issue: GitHub.