Crosstalk-Solutions/project-nomad · warning
Failed to fetch update status
Error message
Failed to fetch update status
What it means
Thrown by the update page's polling loop (setInterval) when api.getSystemUpdateStatus() resolves to a falsy value. It signals the update-status endpoint returned an empty/unparseable body while the UI is in isUpdating mode and polling progress.
Source
Thrown at admin/inertia/pages/settings/update.tsx:76
// window across the admin container restart. If we resurface to 'idle'
// after seeing an advanced stage, treat it as the missed completion.
const seenAdvancedStageRef = useRef(false)
const earlyAccessSetting = useSystemSetting({
key: 'system.earlyAccess', initialData: {
key: 'system.earlyAccess',
value: props.system.earlyAccess,
}
})
useEffect(() => {
if (!isUpdating) return
const interval = setInterval(async () => {
try {
const response = await api.getSystemUpdateStatus()
if (!response) {
throw new Error('Failed to fetch update status')
}
setUpdateStatus(response)
if (ADVANCED_STAGES.has(response.stage)) {
seenAdvancedStageRef.current = true
}
// If we can connect again, hide the connection lost notice
setShowConnectionLostNotice(false)
// Check if update is complete or errored. We also treat a return to
// 'idle' as completion if we previously saw an advanced stage — this
// catches the race where the sidecar's brief 'complete' window passes
// while we're disconnected during the admin container restart.
const isComplete =
response.stage === 'complete' ||
(response.stage === 'idle' && seenAdvancedStageRef.current)
View on GitHub (pinned to 0bd1c6f4f9)
Solutions
- Inspect the network tab for the failing status request's HTTP status/body
- Make the axios wrapper return response.data and not swallow errors — an empty 200 should be surfaced as HTTP detail
- Treat transient poll failures leniently: tolerate N consecutive failures before erroring the UI
- If the backend restarts during update, persist update stage server-side so status recovers
Example fix
// before
const response = await api.getSystemUpdateStatus()
if (!response) {
throw new Error('Failed to fetch update status')
}
// after
const response = await api.getSystemUpdateStatus().catch(() => null)
if (!response) {
pollFailuresRef.current += 1
if (pollFailuresRef.current >= 3) throw new Error('Failed to fetch update status')
return
}
pollFailuresRef.current = 0 Defensive patterns
Strategy: retry
Validate before calling
if (!isUpdating) return // don't poll when not updating
Try / catch
try {
const response = await api.getSystemUpdateStatus()
if (!response) throw new Error('Failed to fetch update status')
failuresRef.current = 0
} catch {
failuresRef.current += 1
if (failuresRef.current >= 3) setError('Lost contact with update status')
} Prevention
- Use React Query's useInterval polling with built-in retry instead of raw setInterval
- Tolerate transient poll failures before surfacing an error
- Clear the interval reliably on unmount to avoid stale polls
When it happens
Trigger: Polling GET /system-update/status during an active update where the request is aborted, returns 204/empty body, an interceptor swallows the body, or the server briefly 502s behind a proxy.
Common situations: Reverse proxy (nginx/traefik) timing out long update requests, the backend restarting mid-update so status is briefly unavailable, or an axios response interceptor returning undefined on error paths.
Related errors
- Failed to start update
- Failed to fetch update logs
- Force reinstall failed
- Failed to dispatch update check
AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27).
Data as JSON: /api/errors/89da3fe9be7a4317.
Report an issue: GitHub.