langgenius/dify · error · NotChatAppError

not_chat_app

not_chat_app

Error message

App mode is invalid.

What it means

HTTP 400 with error_code not_chat_app, raised by GET /installed-apps/<id>/messages when the app's mode is not in {CHAT, AGENT_CHAT, ADVANCED_CHAT}. The messages endpoint only exists for chat-family apps; completion, workflow, and other modes are rejected.

Source

Thrown at api/controllers/console/explore/message.py:86


@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)
                for message in pagination.data
            ]
            return ExploreMessageInfiniteScrollPagination(
                limit=pagination.limit,

View on GitHub (pinned to ef8544b173)

Solutions

  1. Branch the UI on app.mode: route CHAT/AGENT_CHAT/ADVANCED_CHAT to messages, completion to its own view, workflow to its own view.
  2. Before calling messages, read the mode from GET /installed-apps/<id> (InstalledAppInfoResponse.mode) and skip the call for non-chat modes.
  3. If the app should be a chat app, verify the mode was not changed by the owner.
  4. Hide the 'message history' affordance entirely for non-chat apps.

Example fix

// before: always fetch messages
const msgs = await get(`/installed-apps/${id}/messages`);

// after: only for chat-family modes
const CHAT_MODES = ['chat', 'agent-chat', 'advanced-chat'];
if (CHAT_MODES.includes(app.mode)) {
  const msgs = await get(`/installed-apps/${id}/messages`);
}
Defensive patterns

Strategy: type-guard

Validate before calling

const CHAT_MODES = new Set(['chat', 'agent-chat', 'advanced-chat']);
function shouldFetchMessages(app) {
  return CHAT_MODES.has(app.mode);
}
if (!shouldFetchMessages(app)) return; // skip messages call for non-chat apps

Type guard

function isChatModeApp(app) {
  return ['chat', 'agent-chat', 'advanced-chat'].includes(app?.mode);
}

Try / catch

try {
  return await get(messagesUrl(id));
} catch (e) {
  if (e.code === 'not_chat_app') {
    routeToModeSpecificView(app.mode);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /console/explore/installed-apps/<id>/messages on an installed app whose AppMode is completion, workflow, or unknown. The mode check fires after the app is loaded but before MessageService is called.

Common situations: UI routes all installed-app tiles to the messages view regardless of mode; app was migrated from chat to workflow; client hardcodes the messages URL.

Related errors


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