{"record":{"id":"baeeb9cca455eb36","repo":"langgenius/dify","slug":"app-entity-not-found","errorCode":null,"errorMessage":"App entity not found","messagePattern":"App entity not found","errorType":"http","errorClass":"NotFound","httpStatus":404,"severity":"error","filePath":"api/controllers/console/explore/installed_app.py","lineNumber":210,"sourceCode":"\n    @login_required\n    @account_initialization_required\n    @cloud_edition_billing_resource_check(\"apps\")\n    @console_ns.expect(console_ns.models[InstalledAppCreatePayload.__name__])\n    @console_ns.response(200, \"Success\", console_ns.models[SimpleMessageResponse.__name__])\n    @with_current_tenant_id\n    @model_validate(InstalledAppCreatePayload)\n    def post(self, req_data: InstalledAppCreatePayload, current_tenant_id: str):\n        recommended_app = db.session.scalar(\n            select(RecommendedApp).where(RecommendedApp.app_id == req_data.app_id).limit(1)\n        )\n        if recommended_app is None:\n            raise NotFound(\"Recommended app not found\")\n\n        app = db.session.get(App, req_data.app_id)\n\n        if app is None:\n            raise NotFound(\"App entity not found\")\n\n        if not app.is_public:\n            raise Forbidden(\"You can't install a non-public app\")\n\n        installed_app = db.session.scalar(\n            select(InstalledApp)\n            .where(and_(InstalledApp.app_id == req_data.app_id, InstalledApp.tenant_id == current_tenant_id))\n            .limit(1)\n        )\n\n        if installed_app is None:\n            # todo: position\n            recommended_app.install_count += 1\n\n            new_installed_app = InstalledApp(\n                app_id=req_data.app_id,\n                tenant_id=current_tenant_id,\n                app_owner_tenant_id=app.tenant_id,","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/explore/installed_app.py#L192-L228","documentation":"HTTP 404 raised in POST /console/explore/installed-apps after a RecommendedApp row was found, but db.session.get(App, app_id) returned None. This indicates a data-integrity break: the recommended_apps row references an App primary key that no longer exists.","triggerScenarios":"POST /console/explore/installed-apps with an app_id that exists in recommended_apps but whose corresponding row in the apps table has been deleted (hard delete) or never committed. The RecommendedApp foreign-key reference is dangling.","commonSituations":"An admin deleted the App record while the RecommendedApp entry was left in place; a partial/rolled-back migration; manual DB surgery that removed apps without cleaning recommended_apps; multi-tenant workspace teardown that missed the explore table.","solutions":["Report to an admin to remove the orphaned RecommendedApp row (or re-create the missing App) — this is a server-side data inconsistency, not a client mistake.","As an admin, run a sweep: SELECT * FROM recommended_apps ra LEFT JOIN apps a ON ra.app_id = a.id WHERE a.id IS NULL; and delete the orphans.","On the client, fall back to the general Explore listing and skip the broken entry.","Add a cascade or periodic cleanup job so deleting an App also removes its RecommendedApp row."],"exampleFix":"-- before: orphan recommended_apps row points at deleted app\nSELECT ra.app_id FROM recommended_apps ra\nLEFT JOIN apps a ON a.id = ra.app_id\nWHERE a.id IS NULL;\n\n-- after: remove orphans so the listing stays consistent\nDELETE ra FROM recommended_apps ra\nLEFT JOIN apps a ON a.id = ra.app_id\nWHERE a.id IS NULL;","handlingStrategy":"try-catch","validationCode":"// Client cannot validate server-side data integrity; preflight only confirms recommend status\nasync function appExists(appId) {\n  const r = await fetch(`/console/explore/apps`);\n  const list = await r.json();\n  return (list.data || []).some(a => a.app_id === appId);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await post('/console/explore/installed-apps', { app_id });\n} catch (e) {\n  if (e.status === 404 && /App entity not found/.test(e.message)) {\n    reportOrphanToAdmin(app_id); // data integrity issue, server-side fix required\n  } else throw e;\n}","preventionTips":["Treat 'App entity not found' as a server data-integrity defect; escalate to an admin.","Admins should cascade App deletion to recommended_apps to prevent orphans.","Periodic integrity sweep: LEFT JOIN apps on recommended_apps.app_id for NULLs."],"tags":["rest-api","explore","data-integrity","orphan-reference","dify"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}