TryGhost/Ghost · warning · Error

Failed to fetch changelog: ${response.status}

Error message

Failed to fetch changelog: ${response.status}

What it means

useChangelog is a TanStack Query useQuery hook that fetches https://ghost.org/changelog.json to populate the in-admin 'What's New' panel. If the fetch resolves but response.ok is false (HTTP 4xx/5xx), it throws with the status code. The error surfaces as the query's error state and triggers React Query's retry/errorBoundary behavior.

Source

Thrown at apps/admin/src/whats-new/hooks/use-changelog.ts:51

        posts: z.array(ChangelogEntrySchema).default([]),
        changelogUrl: z.string().url().default("https://ghost.org/changelog"),
    })
    .transform((data) => ({
        entries: data.posts,
        changelogUrl: data.changelogUrl,
    }));

export type RawChangelogResponse = z.input<typeof ChangelogResponseSchema>;
export type ChangelogResponse = z.output<typeof ChangelogResponseSchema>;

export const useChangelog = () =>
    useQuery({
        queryKey: ["changelog"],
        queryFn: async () => {
            const response = await fetch("https://ghost.org/changelog.json");

            if (!response.ok) {
                throw new Error(`Failed to fetch changelog: ${response.status}`);
            }

            const data = (await response.json()) as unknown;

            return ChangelogResponseSchema.parse(data);
        },
        staleTime: Infinity,
    });

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Check browser DevTools Network tab for the actual status and response body of the changelog.json request.
  2. If behind a proxy, ensure ghost.org is allowlisted or disable the changelog panel in offline environments.
  3. React Query retries by default (3 attempts) — if transient, the error clears on retry; for permanent blocks, suppress the panel via the feature flag or conditional rendering on query error.
  4. If the endpoint moved, update the URL in use-changelog.ts:48.
Defensive patterns

Strategy: fallback

Try / catch

// useChangelog uses React Query; consume the error state in the component:
const {data, error, isLoading} = useChangelog();
if (error) {
  // render the panel in a degraded/hidden state
  return null;
}

Prevention

When it happens

Trigger: The fetch to ghost.org/changelog.json returns a non-2xx status. Common causes: a 404 if the endpoint path changes, a 403 if Cloudflare blocks the request (geo or bot rules), a 5xx during a Ghost infra outage, or a captive-portal/proxy returning a 200-shaped error page that still has ok=false. Network failures (fetch rejects) produce a different error (TypeError) before this line.

Common situations: Corporate proxy or firewall blocks or rewrites the request. Ghost infra is temporarily down. The admin is loaded in an environment without internet (air-gapped, local-only dev). A browser extension intercepts the request. DNS resolution returns a captive portal page.

Related errors


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