windmill-labs/windmill · error · Error

App not found

Error message

App ${appPath} not found

What it means

This CLI error is raised during `wmill app push`/sync when the remote workspace returns no app for the given path: `wmill.getAppByPath` resolves to a falsy value (404) and the code throws explicitly. It means the app you are trying to update does not exist remotely under that exact path.

Solutions

  1. Create the app first (wmill app push creates it if missing — check you didn't pass a flag/mode that only edits) or verify the command mode you used
  2. Confirm the exact remote path in the Windmill UI and fix the path in your local app folder/app.yaml
  3. Run `wmill workspace switch` (or pass the right workspace) to make sure you target the workspace that owns the app
  4. Check for typos, extra whitespace, or case differences in the path

Example fix

// before
await wmill.updateApp({ workspace, path: "f/apps/dasboard", ... });
// after (typo fixed and app verified to exist)
const app = await wmill.getAppByPath({ workspace, path: "f/apps/dashboard" });
if (!app) throw new Error("create the app first: wmill app push");
Defensive patterns

Strategy: type-guard

Validate before calling

const remote = await wmill.getAppByPath({ workspace: ws, path: appPath });
if (!remote) {
  console.error(`App ${appPath} not found in workspace ${ws}; create it or fix the path before updating.`);
  process.exit(1);
}

Type guard

function appExists(app: { path?: string } | null | undefined): app is { path: string } {
  return !!app && typeof app.path === 'string';
}

Try / catch

try {
  await wmill.updateApp({ workspace, path: appPath, body });
} catch (e) {
  if (String(e).includes('not found')) {
    console.error(`App ${appPath} does not exist remotely — run 'wmill app push' to create it or verify the path/workspace.`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Running an app sync/push command with --path (or an app metadata path) pointing to an app that was never created, was deleted, was renamed, or whose path casing/spacing differs from the remote one, in a different workspace than expected.

Common situations: Typo in the app path in the local app folder; pushing to a fresh workspace/instance where the app was never created; the app was deleted by a teammate; switching workspaces (the CLI workspace is not the one containing the app); path changed after a rename while local files still use the old one.

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


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

Appendix: source

Thrown at cli/src/commands/app/app.ts:481

  })
  .command(
    "set-permissioned-as",
    "Set the on_behalf_of_email for an app (requires admin or wm_deployers group)"
  )
  .arguments("<path:string> <email:string>")
  .action((async (opts: any, appPath: string, email: string) => {
    const workspace = await resolveWorkspace(opts);
    await requireLogin(opts);

    const { lookupUsernameByEmail } = await import("../../core/permissioned_as.ts");
    const cache = new Map<string, { username: string; email: string }>();
    const username = await lookupUsernameByEmail(workspace.workspaceId, email, cache);

    const remote = await wmill.getAppByPath({
      workspace: workspace.workspaceId,
      path: appPath,
    });
    if (!remote) throw new Error(`App ${appPath} not found`);

    // Only spread remote.policy — spreading the full remote object would include
    // `value` and trigger a new app version on every call. EditApp has all-Option
    // fields, so a minimal body only updates the policy column.
    await wmill.updateApp({
      workspace: workspace.workspaceId,
      path: appPath,
      requestBody: {
        policy: {
          ...(remote.policy as any),
          on_behalf_of: `u/${username}`,
          on_behalf_of_email: email,
        } as any,
        preserve_on_behalf_of: true,
        // Preserve any user draft at this path (see backend skip_draft_deletion).
        skip_draft_deletion: true,
      },
    });

View on GitHub (pinned to e474e8803c)