TryGhost/Ghost · error · Error

Failed to fetch comments

Error message

Failed to fetch comments

What it means

comments.browse() GETs /members/api/comments/post/{postId} with pagination and filter params to load the comment thread for a post. If the response is not ok, it throws. A side-effect after the response (capturing firstCommentCreatedAt for pagination dedup) only runs on success because it is chained on the resolved promise.

Source

Thrown at apps/comments-ui/src/utils/api.ts:157

                    params.set('filter', filter);
                }
                params.set('page', page.toString());
                if (order) {
                    params.set('order', order);
                }
                const url = endpointFor({type: 'members', resource: `comments/post/${postId}`, params: `?${params.toString()}`});
                const response = makeRequest({
                    url,
                    method: 'GET',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    credentials: 'same-origin'
                }).then(function (res) {
                    if (res.ok) {
                        return res.json();
                    } else {
                        throw new Error('Failed to fetch comments');
                    }
                });

                if (!firstCommentCreatedAt) {
                    response.then((body) => {
                        const firstComment = body.comments[0];
                        if (firstComment) {
                            firstCommentCreatedAt = firstComment.created_at;
                        }
                    });
                }

                return response;
            },
            async replies({commentId, afterReplyId, limit, page}: {commentId: string; afterReplyId?: string; limit?: number | 'all'; page?: number}) {
                if (limit === 'all') {
                    // Paginate by page, not an `id:>` cursor: replies are ordered by
                    // created_at, so an id cursor can re-fetch or skip replies (BER-3706).

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Check the Network tab for the comments GET status code.
  2. If 401/403, ensure the member session cookie is present and valid; re-init the member identity.
  3. If 404, confirm the postId is correct and that comments are enabled on that post.
  4. Handle the rejected promise in the UI to show an empty or error state rather than a blank thread.
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidPostId(postId: string | null): boolean {
  return typeof postId === 'string' && postId.length > 0;
}

Try / catch

try {
  const data = await api.comments.browse({page: 1, postId});
} catch (e) {
  if (e instanceof Error && e.message === 'Failed to fetch comments') {
    // show empty/error state in the comment list
  }
}

Prevention

When it happens

Trigger: The comments browse GET returns 4xx/5xx. The postId is invalid or the post has comments disabled (404/403), the member session expired (401), the server is overloaded (503), or the request is rate-limited (429). If the request fails, the firstCommentCreatedAt pagination anchor is not set, so subsequent calls have no dedup filter.

Common situations: A post with comments disabled by the author returns 404. The member's cookie expired between page load and the comments fetch. A spike in traffic triggers rate limiting. The postId passed does not match any post.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/31db747efa9c6c19. Report an issue: GitHub.