actualbudget/actual · warning
Failed to fetch catalog: ${response.statusText}
Error message
Failed to fetch catalog: ${response.statusText} What it means
useThemeCatalog's fetchCatalog fetches the theme catalog from CATALOG_URL and throws 'Failed to fetch catalog: <statusText>' when response.ok is false (non-2xx HTTP status). The statusText is embedded so the developer can see why the request failed (e.g. Not Found, Service Unavailable). The error is captured and stored via setError rather than thrown to the caller.
Source
Thrown at packages/desktop-client/src/hooks/useThemeCatalog.ts:24
/**
* Custom hook to fetch and manage the theme catalog from GitHub.
*/
export function useThemeCatalog() {
const [data, setData] = useState<CatalogTheme[] | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchCatalog = async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch(CATALOG_URL);
if (!response.ok) {
throw new Error(`Failed to fetch catalog: ${response.statusText}`);
}
const data = await response.json();
// Validate that data is an array
if (!Array.isArray(data)) {
throw new Error('Invalid catalog format: expected an array');
}
setData(data);
} catch (err) {
setError(
err instanceof Error ? err.message : 'Failed to load theme catalog',
);
} finally {
setIsLoading(false);
}
};View on GitHub (pinned to d4334cb6e6)
Solutions
- Check CATALOG_URL in useThemeCatalog.ts and confirm it resolves correctly (open it in a browser or with curl -I)
- Retry later or add retry/backoff logic — the error often indicates a transient server or network problem
- Serve the catalog locally or bundle a fallback static catalog when offline
- Inspect response.status (not just statusText) for richer diagnostics in the error message
Example fix
// before
if (!response.ok) {
throw new Error(`Failed to fetch catalog: ${response.statusText}`);
}
// after
if (!response.ok) {
throw new Error(`Failed to fetch catalog: ${response.status} ${response.statusText} (${CATALOG_URL})`);
} Defensive patterns
Strategy: retry
Validate before calling
// Before fetching, check connectivity when available:
if (typeof navigator !== 'undefined' && navigator.onLine === false) {
console.warn('Offline: theme catalog will not load');
} Type guard
const isHttpOk = (r: Response): r is Response & { ok: true } => r.ok; Try / catch
const { catalog, error } = useThemeCatalog();
if (error?.startsWith('Failed to fetch catalog')) {
render(<FallbackThemeList />); // or a Retry button re-running fetchCatalog
} Prevention
- Add retry with exponential backoff around the catalog fetch
- Pin CATALOG_URL via configuration so it can be corrected without a rebuild
- Check the endpoint's uptime and status codes with curl -I during development
- Bundle a minimal fallback catalog for offline use
When it happens
Trigger: The catalog URL returns 404 (wrong/removed URL), 403 (blocked), 5xx (server error), or is redirected to an error page while useThemeCatalog mounts and fetchCatalog runs.
Common situations: Offline development environments or corporate proxies blocking the request; the catalog host being down; CATALOG_URL pointing to a stale domain; rate limiting returning 429.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to fetch CSS from ${url}: ${response.status} ${respon
- ${text}
- API request redirected
- getServerErrorReason(json)
- text (raw server response body)
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/ef7a3799ee8edf3c.
Report an issue: GitHub.