actualbudget/actual · error · LazyLoadFailedError
Error: failed loading lazy-loaded module ${name}
Error message
Error: failed loading lazy-loaded module ${name} What it means
LoadComponent lazy-imports modal components by name; when the dynamic `importer()` promise rejects (even after 5 exponential-backoff retries via promiseRetry), it throws LazyLoadFailedError wrapping the underlying error and the module name. This means the code-split chunk for the modal could not be fetched or evaluated, so the UI cannot render it.
Source
Thrown at packages/desktop-client/src/components/util/LoadComponent.tsx:63
}
})
.catch(retry),
{
retries: 5,
},
).catch(e => {
if (!isUnmounted) {
setError(e);
}
});
return () => {
isUnmounted = true;
};
}, [name, importer]);
if (error) {
throw new LazyLoadFailedError(name, error);
}
if (!Component) {
return (
<View
style={{
flex: 1,
gap: 20,
justifyContent: 'center',
alignItems: 'center',
...styles.delayedFadeIn,
}}
>
{message && (
<Block style={{ marginBottom: 20, fontSize: 18 }}>{message}</Block>
)}
<AnimatedLoading width={25} color={theme.pageTextDark} />
</View>View on GitHub (pinned to d4334cb6e6)
Solutions
- Reload the page (or force a hard refresh) to fetch the current build's chunk manifest.
- Check the browser Network tab for the failing chunk request — 404 indicates a stale build; fix by redeploying or reloading.
- Verify the importer path and the exported component name still match after refactors (`module[name]` must exist).
- Add an error boundary around LoadComponent that offers a 'reload' action, and/or auto-reload once when LazyLoadFailedError is chunk-load related.
Example fix
// before
if (error) {
throw new LazyLoadFailedError(name, error);
}
// after
if (error) {
if (isFirstLoadFailure) {
window.location.reload(); // recover from stale-chunk deployments
return null;
}
throw new LazyLoadFailedError(name, error);
} Defensive patterns
Strategy: try-catch
Validate before calling
// before relying on a lazy modal, verify navigator.onLine and that the app build is current
if (!navigator.onLine) {
showOfflineNotice();
return;
}
// optionally probe the chunk URL
const res = await fetch(chunkUrl, { method: 'HEAD' });
if (!res.ok) window.location.reload(); Type guard
import { LazyLoadFailedError } from '@actual-app/core/shared/errors';
function isLazyLoadFailed(e: unknown): e is LazyLoadFailedError {
return e instanceof LazyLoadFailedError;
} Try / catch
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) =>
isLazyLoadFailed(error) ? (
<RetryLoadScreen onReload={() => { window.location.reload(); }} />
) : (
<UnexpectedErrorScreen error={error} onDismiss={resetErrorBoundary} />
)
}
>
<LoadComponent name="ManageRulesModal" importer={...} />
</ErrorBoundary> Prevention
- Always wrap lazy-loaded components in an error boundary that offers reload/retry.
- Auto-reload once on chunk-load failures to recover from deployments that invalidated old chunks.
- Keep a version/build hash check so stale tabs detect new deploys and prompt to refresh.
- After renaming a lazily loaded component, update every importer call and its `name` prop together.
When it happens
Trigger: A failed dynamic import: network outage or interrupted connection while fetching the chunk, deploying a new app version so old HTML references chunk filenames that no longer exist, a service worker caching stale chunks, or the importer resolving but `module[name]` being undefined after a rename.
Common situations: Users with a long-lived open tab crossing a deployment (stale index.html requesting deleted hashed chunks); flaky/offline connections on mobile; CDN misconfiguration returning HTML instead of JS for chunk URLs.
Related errors
- Could not resolve on-disk budget id for syncId ${syncId} aft
- results.reason || results.error_code
- results.reason || results.error
- Failed to fetch catalog: ${response.statusText}
- Failed to fetch CSS from ${url}: ${response.status} ${respon
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f494be93740b5def.
Report an issue: GitHub.