langgenius/dify · error · AppNotFoundError
app_not_found
app_not_found
Error message
App not found.
What it means
Raised by the app_data_view decorator when an app is bound to an Agent App with AgentScope.WORKFLOW_ONLY. Such hidden backing apps power a roster Agent but are not part of the general app management plane, so generic app routes reject them outright. Returned as code 'app_not_found' to avoid leaking the hidden backing app.
Source
Thrown at api/controllers/console/app/wraps.py:83
(rename/icon sync, archive, API enablement), so it additionally requires
workspace ``agent.manage`` on top of the route's existing App permission
checks when RBAC is enabled. A no-op for non-agent Apps. Must be placed
above ``get_app_model`` so the ``app_id`` path parameter is still present.
"""
@wraps(view)
def decorated(*args: P.args, **kwargs: P.kwargs) -> R:
raw_app_id = kwargs.get("app_id") or kwargs.get("resource_id")
if raw_app_id is not None:
app_model = _load_app_model_from_scoped_session(str(raw_app_id))
binding = (
app_model.agent_app_binding_with_session(session=db.session(), include_archived=True)
if app_model is not None
else None
)
if binding is not None:
if binding.scope == AgentScope.WORKFLOW_ONLY:
raise AppNotFoundError()
if dify_config.RBAC_ENABLED:
current_user, current_tenant_id = current_account_with_tenant()
enforce_rbac_access(
tenant_id=current_tenant_id,
account_id=current_user.id,
resource_type=RBACResourceScope.WORKSPACE,
scene=RBACPermission.AGENT_MANAGE,
resource_required=False,
)
return view(*args, **kwargs)
return decorated
def _get_injected_session(args: tuple[object, ...]) -> Session | None:
"""Return the request session inserted by `with_session`, if this handler has been migrated."""
if len(args) < 2:
return NoneView on GitHub (pinned to ef8544b173)
Solutions
- Use the agent App id (the one shown in the console), not the hidden workflow-only backing app id.
- Inspect AgentAppBinding to find the user-facing app id associated with the backing workflow.
- Filter UI lists to exclude apps with a WORKFLOW_ONLY binding.
Defensive patterns
Strategy: validation
Validate before calling
const app = await get(`/apps/${appId}`);
if (app.agent_app_binding?.scope === 'workflow_only') {
// redirect to the user-facing agent app id instead
} Try / catch
try {
await get(`/apps/${appId}/...`);
} catch (e) {
if (e.code === 'app_not_found' && isAgentBackingAppId(appId)) {
// resolve and use the agent app id instead
} else { throw e; }
} Prevention
- Never expose hidden workflow-only backing app ids in the UI; surface the agent app id.
- Filter app lists to exclude apps whose AgentAppBinding.scope is WORKFLOW_ONLY.
When it happens
Trigger: Any generic app-management route decorated with @app_data_view that receives the app_id of a hidden workflow-only backing app behind a roster Agent (e.g. hitting /apps/{app_id}/... on the backing App rather than the Agent App).
Common situations: Frontend mistakenly targets the backing workflow app id instead of the agent app id; URL copy/paste of the wrong id from the database; tooling that lists all App rows hits the hidden one.
Related errors
- Dataset not found for pipeline
- Conversation Not Exists.
- not_found
- Webhook trigger not found for this node
- Trigger not found
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/583b88cbbeeb35a6.
Report an issue: GitHub.