{"record":{"id":"e1a57b7559ea594e","repo":"Budibase/budibase","slug":"app-not-found","errorCode":null,"errorMessage":"App not found","messagePattern":"App not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/server/src/middleware/recaptcha.ts","lineNumber":29,"sourceCode":"  const workspaceId = context.getWorkspaceId()\n  // no app ID, requests are not targeting an app\n  // if not production app - this is in the builder, recaptcha isn't enabled\n  if (!workspaceId || !isProdWorkspaceID(workspaceId)) {\n    return next()\n  }\n  if (!(await features.isRecaptchaEnabled())) {\n    return next()\n  }\n  // builder users can skip validation if request comes from the builder\n  if (\n    sdk.users.isBuilder(ctx.user) &&\n    ctx.headers[Header.CLIENT] === ClientHeader.BUILDER\n  ) {\n    return next()\n  }\n  const app = await cache.workspace.getWorkspaceMetadata(workspaceId)\n  if (\"state\" in app && app.state === cache.workspace.WorkspaceState.INVALID) {\n    throw new Error(\"App not found\")\n  }\n  if ((app as Workspace).features?.recaptchaEnabled) {\n    const cookie = utils.getCookie<RecaptchaSessionCookie>(\n      ctx,\n      Cookie.RecaptchaSession\n    )\n    if (!cookie) {\n      ctx.status = 498\n      return\n    }\n    const verified = await isRecaptchaVerified(cookie.sessionId)\n    if (!verified) {\n      ctx.status = 498\n      return\n    }\n  }\n  return next()\n}","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/middleware/recaptcha.ts#L11-L47","documentation":"The recaptcha middleware resolves app metadata from the workspace cache before applying reCAPTCHA checks. If the cache returns an entry marked INVALID (the app doc cannot be resolved), it throws 'App not found' instead of continuing to the route handler.","triggerScenarios":"An HTTP request (not from the builder client) whose workspaceId/appId resolves to invalid or deleted app metadata in cache.workspace.getWorkspaceMetadata - e.g. requesting an app URL for an app that was deleted or whose DB is missing.","commonSituations":"Hitting a published app URL after the app was deleted; stale/misconfigured proxy routing to a nonexistent appId; dev environments where the CouchDB app database was wiped but DNS/URL still points at the old app id.","solutions":["Confirm the appId/workspaceId in the request URL matches an existing app (check the app's doc in CouchDB).","Republish or recreate the app if it was deleted.","Clear the app metadata cache / restart services so invalid cache entries are re-fetched.","Check proxy/ReverseProxy config so requests aren't routed with a stale app id."],"exampleFix":"// before\ncurl https://host/app-id-that-was-deleted\n// after\ncurl https://host/correct-app-id  (or republish the app first)","handlingStrategy":"try-catch","validationCode":"const meta = await cache.workspace.getWorkspaceMetadata(workspaceId)\nif (\"state\" in meta && meta.state === cache.workspace.WorkspaceState.INVALID) throw new Error(\"App not found\")","typeGuard":"const isValidApp = (m: unknown): m is Workspace => typeof m === \"object\" && m !== null && !(\"state\" in m && (m as any).state === \"invalid\")","tryCatchPattern":"try {\n  await next()\n} catch (e) {\n  if (e.message === \"App not found\") {\n    ctx.status = 404\n    ctx.body = { message: \"App not found\" }\n    return\n  }\n  throw e\n}","preventionTips":["Verify the appId in the URL matches a published app","Invalidate/rebuild metadata cache after deleting apps","Check proxy routing rules for stale app ids","Confirm CouchDB holds the app's database"],"tags":["http","middleware","app-resolution"],"backgroundTag":"app-not-found","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}