#15822·chatwoot

[BUG] Conversation list stuck in infinite loading spinner on API failure/timeout (CLEAR_LIST_LOADING_STATUS not called in catch/finally)

Author: md-riazCreated Sep 15, 2026Updated Sep 16, 2026
LabelsBug

Describe the bug

In the conversation dashboard, if ConversationApi.get or ConversationApi.filter fails (e.g., due to a temporary network blip, an HTTP 500/504 gateway timeout, or a slow request timeout), the conversation list in the left sidebar enters an infinite loading spinner state and never recovers.

Looking at app/javascript/dashboard/store/modules/conversations/actions.js:

javascript
  fetchAllConversations: async ({ commit, state, dispatch }) => {
    commit(types.SET_LIST_LOADING_STATUS);
    try {
      const params = state.conversationFilters;
      const {
        data: { data },
      } = await ConversationApi.get(params);
      buildConversationList(
        { commit, dispatch },
        params,
        data,
        params.assigneeType
      );
    } catch (error) {
      // Handle error
    }
  },

  fetchFilteredConversations: async ({ commit, dispatch }, params) => {
    commit(types.SET_LIST_LOADING_STATUS);
    try {
      const { data } = await ConversationApi.filter(params);
      buildConversationList(
        { commit, dispatch },
        params,
        data,
        'appliedFilters'
      );
    } catch (error) {
      // Handle error
    }
  },

Notice that:

  1. commit(types.SET_LIST_LOADING_STATUS) sets getChatListLoading to true.
  2. commit(types.CLEAR_LIST_LOADING_STATUS) is only invoked inside buildConversationList(...).
  3. If ConversationApi.get or ConversationApi.filter rejects/throws, the catch (error) block does nothing (// Handle error), silently swallowing the error without ever clearing types.SET_LIST_LOADING_STATUS.

In ConversationList.vue:

xml
    <div v-if="isLoading" class="flex justify-center my-4">
      <Spinner class="text-n-brand" />
    </div>

Because isLoading (chatListLoading) remains true permanently, the user is stuck with a spinning blue loader in the left sidebar and an empty list of chats, even when navigating or switching between conversations, until they perform a hard page refresh (Ctrl+Shift+R).

To Reproduce

  1. Open Chatwoot dashboard (/app/accounts/{id}/conversations/{id}).
  2. Simulate a network failure or temporary 500/504 response for GET /api/v1/accounts/{id}/conversations?... (e.g. using browser DevTools Network Request Blocking or throttling/failing the request).
  3. Observe that the left conversation list displays a spinning loader indefinitely.
  4. Switching tabs or clicking does not clear the spinner because the Vuex loading state is never reset on failure.

Expected behavior

If the conversation fetch fails:

  1. types.CLEAR_LIST_LOADING_STATUS should always be committed (e.g., in a finally block or inside catch).
  2. An error state or retry button / alert should ideally be displayed instead of an infinite spinner.

Environment

Linux VM / Docker / All self-hosted & cloud environments.

Proposed Fix

In app/javascript/dashboard/store/modules/conversations/actions.js, ensure CLEAR_LIST_LOADING_STATUS is always executed, either in catch or via a finally block:

javascript
  fetchAllConversations: async ({ commit, state, dispatch }) => {
    commit(types.SET_LIST_LOADING_STATUS);
    try {
      const params = state.conversationFilters;
      const {
        data: { data },
      } = await ConversationApi.get(params);
      buildConversationList(
        { commit, dispatch },
        params,
        data,
        params.assigneeType
      );
    } catch (error) {
      commit(types.CLEAR_LIST_LOADING_STATUS);
      // Optional: dispatch toast / error alert
    }
  },

  fetchFilteredConversations: async ({ commit, dispatch }, params) => {
    commit(types.SET_LIST_LOADING_STATUS);
    try {
      const { data } = await ConversationApi.filter(params);
      buildConversationList(
        { commit, dispatch },
        params,
        data,
        'appliedFilters'
      );
    } catch (error) {
      commit(types.CLEAR_LIST_LOADING_STATUS);
    }
  },