langgenius/dify · error · NotFound

Recommended app not found

Error message

Recommended app not found

What it means

HTTP 404 raised by POST /console/explore/installed-apps when no RecommendedApp row matches the submitted app_id. The explore store is a separate table from App; only apps explicitly published to RecommendedApp are installable through this endpoint. The check runs before the App entity is even loaded.

Source

Thrown at api/controllers/console/explore/installed_app.py:205

                "installed_apps": installed_app_list,
                "has_more": has_more,
                "next_cursor": _encode_installed_app_cursor(next_cursor) if next_cursor else None,
            },
        )

    @login_required
    @account_initialization_required
    @cloud_edition_billing_resource_check("apps")
    @console_ns.expect(console_ns.models[InstalledAppCreatePayload.__name__])
    @console_ns.response(200, "Success", console_ns.models[SimpleMessageResponse.__name__])
    @with_current_tenant_id
    @model_validate(InstalledAppCreatePayload)
    def post(self, req_data: InstalledAppCreatePayload, current_tenant_id: str):
        recommended_app = db.session.scalar(
            select(RecommendedApp).where(RecommendedApp.app_id == req_data.app_id).limit(1)
        )
        if recommended_app is None:
            raise NotFound("Recommended app not found")

        app = db.session.get(App, req_data.app_id)

        if app is None:
            raise NotFound("App entity not found")

        if not app.is_public:
            raise Forbidden("You can't install a non-public app")

        installed_app = db.session.scalar(
            select(InstalledApp)
            .where(and_(InstalledApp.app_id == req_data.app_id, InstalledApp.tenant_id == current_tenant_id))
            .limit(1)
        )

        if installed_app is None:
            # todo: position
            recommended_app.install_count += 1

View on GitHub (pinned to ef8544b173)

Solutions

  1. Verify the app_id is currently returned by GET /console/explore/apps (the Explore listing) before calling install.
  2. If the id came from a cached/stored value, refresh it from the Explore list the user is currently viewing.
  3. If you expect the app to be installable but it is not listed, have an admin re-add it to RecommendedApp via the Explore management surface.
  4. Confirm the request hits the same environment (same DB) that listed the app originally.

Example fix

// before: app_id from stale local storage
await post('/console/explore/installed-apps', { app_id: cachedId });

// after: resolve id from the live Explore listing
const listing = await get('/console/explore/apps');
const target = listing.data.find(a => a.app_id === cachedId);
if (!target) throw new UserError('App no longer available in Explore');
await post('/console/explore/installed-apps', { app_id: target.app_id });
Defensive patterns

Strategy: validation

Validate before calling

// Resolve app_id from the live Explore listing before installing
async function getRecommendedAppId(desiredId) {
  const res = await fetch('/console/explore/apps', { headers: authHeaders() });
  const list = await res.json();
  const found = (list.data || []).find(a => a.app_id === desiredId);
  return found ? found.app_id : null; // null => do not call install
}

Type guard

function isInstallableAppId(value, listing) {
  return typeof value === 'string'
    && /^[0-9a-fA-F-]{36}$/.test(value)
    && listing.some(a => a.app_id === value);
}

Try / catch

try {
  await post('/console/explore/installed-apps', { app_id });
} catch (e) {
  if (e.status === 404 && /Recommended app not found/.test(e.message)) {
    refreshExploreListing(); // app no longer recommended
  } else throw e;
}

Prevention

When it happens

Trigger: POST /console/explore/installed-apps with a body {"app_id": "<id>"} where <id> is not present in the recommended_apps table. Happens with typos, with app ids scraped from a different environment, or with apps that were delisted from Explore after the client cached the id.

Common situations: Stale client cache pointing at a delisted app; cross-environment id (test id sent to prod); app exists in the App table but was never published to the Explore listing; admin removed the app from the recommended store.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/60916851cbf3376f. Report an issue: GitHub.