langgenius/dify · error · AppUnavailableError
app_unavailable
app_unavailable
Error message
App unavailable, please check your app configurations.
What it means
HTTP 400 with error_code app_unavailable, raised by GET /console/explore/installed-apps/<id>/messages when installed_app.app_with_session(session) returns None. The InstalledApp exists but its related App cannot be loaded, so message pagination cannot proceed.
Source
Thrown at api/controllers/console/explore/message.py:82
ExploreMessageInfiniteScrollPagination,
ResultResponse,
SuggestedQuestionsResponse,
)
@console_ns.route(
"/installed-apps/<uuid:installed_app_id>/messages",
endpoint="installed_app_messages",
)
class MessageListApi(InstalledAppResource):
@console_ns.doc(params=query_params_from_model(MessageListQuery))
@console_ns.response(200, "Success", console_ns.models[ExploreMessageInfiniteScrollPagination.__name__])
@with_current_user
def get(self, current_user: Account, installed_app: InstalledApp):
session = db.session()
app_model = installed_app.app_with_session(session=session)
if app_model is None:
raise AppUnavailableError()
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()
args = MessageListQuery.model_validate(request.args.to_dict())
try:
pagination = MessageService.pagination_by_first_id(
app_model,
current_user,
args.conversation_id,
args.first_id or None,
args.limit,
session=session,
)
adapter = TypeAdapter(ExploreMessageListItem)
items = [
adapter.validate_python(MessageResponseSource(message, session=session), from_attributes=True)View on GitHub (pinned to ef8544b173)
Solutions
- Guard the UI: before opening messages, verify the app via GET /installed-apps/<id> and handle app_unavailable.
- Have the owning tenant restore or republish the App.
- Clean up installed_apps rows whose App is missing (admin sweep).
- Show a 'no longer available' state and offer to remove the installed-app entry.
Example fix
// before: open message list directly
const msgs = await get(`/installed-apps/${id}/messages`);
// after: preflight the app and degrade gracefully
const app = await get(`/installed-apps/${id}`);
if (!app) return showUnavailable();
const msgs = await get(`/installed-apps/${id}/messages`); Defensive patterns
Strategy: validation
Validate before calling
// Confirm the backing app is reachable before loading messages
const app = await get(`/console/explore/installed-apps/${id}`);
if (!app) return; // backing App unavailable; do not call messages Type guard
function appIsAvailable(app) {
return app !== null && app !== undefined;
} Try / catch
try {
return await get(`/console/explore/installed-apps/${id}/messages`);
} catch (e) {
if (e.code === 'app_unavailable') {
showAppUnavailableState(id);
return null;
}
throw e;
} Prevention
- Gate the messages view on a successful GET of the installed app.
- Treat app_unavailable as terminal for that session and offer re-install.
- Admins: remove installed_apps rows whose App is missing.
When it happens
Trigger: GET messages for an installed app whose underlying App row is gone or unreadable. Triggered by the same conditions as error 743 (owner deleted/unpublished) but hit on the messages sub-resource.
Common situations: App owner deleted the app after another tenant installed it; relational mapping broken (app_id FK stale); the installed-app tile is still on the dashboard but the backing app is dead.
Related errors
- not_chat_app
- Conversation Not Exists.
- First Message Not Exists.
- Message Not Exists.
- Recommended app not found
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/9ec177a065b3e1b3.
Report an issue: GitHub.