{"record":{"id":"7f65030f3cc2a7c0","repo":"RocketChat/Rocket.Chat","slug":"app-not-found","errorCode":null,"errorMessage":"App not found","messagePattern":"App not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/client/apps/orchestrator.ts","lineNumber":130,"sourceCode":"\t\t\tmarketplace: true,\n\t\t\tversion,\n\t\t\tpermissionsGranted,\n\t\t})) as { app: App };\n\t\treturn app;\n\t}\n\n\tpublic async updateApp(appId: string, version: string, permissionsGranted?: IPermission[]): Promise<App> {\n\t\tconst result = await sdk.rest.post<'/apps/:id'>(`/apps/${appId}`, {\n\t\t\tappId,\n\t\t\tmarketplace: true,\n\t\t\tversion,\n\t\t\tpermissionsGranted,\n\t\t});\n\n\t\tif ('app' in result) {\n\t\t\treturn result.app;\n\t\t}\n\t\tthrow new Error('App not found');\n\t}\n\n\tpublic async buildExternalUrl(appId: string, purchaseType: 'buy' | 'subscription' = 'buy', details = false): Promise<IAppExternalURL> {\n\t\tconst result = await sdk.rest.get('/apps/buildExternalUrl', {\n\t\t\tappId,\n\t\t\tpurchaseType,\n\t\t\tdetails: `${details}`,\n\t\t});\n\n\t\tif ('url' in result) {\n\t\t\treturn result;\n\t\t}\n\n\t\tthrow new Error('Failed to build external url');\n\t}\n\n\tpublic async buildExternalAppRequest(appId: string) {\n\t\tconst result = await sdk.rest.get('/apps/buildExternalAppRequest', {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/client/apps/orchestrator.ts#L112-L148","documentation":"Thrown by AppClientOrchestrator.updateApp after POST /apps/:id returns a body without an `app` key. The message 'App not found' is misleading — the guard is a structural check on the response, not a 404 lookup. The real cause is that the server did not return the expected { app: App } envelope after an update.","triggerScenarios":"Updating an app whose id does not exist (server returns an error-shaped 200), the app failed to update due to missing permissions/version, or the server returned a different envelope such as { success: true } without nesting the app. The structural 'app' in result check fails and this generic message is thrown.","commonSituations":"Calling updateApp for an appId that was uninstalled elsewhere; the user lacks 'manage-apps'; the requested version is not installed/available; server version returns a different update response shape; apps-engine not enabled so the route returns a non-app body.","solutions":["Inspect the raw POST /apps/:id response in DevTools to see what shape the server actually returned.","Verify the appId still exists (call getApp/getInstalledApps first) and the target version is valid.","Confirm the caller has 'manage-apps' permission and the apps engine is enabled.","Treat the message as a response-shape error, not literally 'not found', when debugging."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasAppKey(r: unknown): r is { app: App } {\n  return typeof r === 'object' && r !== null && 'app' in r;\n}","tryCatchPattern":"try {\n  const app = await orchestrator.updateApp(appId, version, perms);\n} catch (e) {\n  if ((e as Error).message === 'App not found') {\n    // misleading: response shape invalid; check network + permissions\n  }\n}","preventionTips":["Confirm the appId still exists before updating (call getApp first).","Ensure the caller has 'manage-apps' permission.","Do not read the message literally as a 404; it is a response-shape error."],"tags":["apps-engine","marketplace","rest","response-shape","misleading-message"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}