Crosstalk-Solutions/project-nomad · warning
Failed to fetch update logs
Error message
Failed to fetch update logs
What it means
Thrown by handleViewLogs when api.getSystemUpdateLogs() resolves falsy (or the request rejects). The catch then discards the underlying cause and sets the generic string on the page.
Source
Thrown at admin/inertia/pages/settings/update.tsx:141
try {
setError(null)
seenAdvancedStageRef.current = false
setIsUpdating(true)
const response = await api.startSystemUpdate()
if (!response || !response.success) {
throw new Error('Failed to start update')
}
} catch (err: any) {
setIsUpdating(false)
setError(err.response?.data?.error || err.message || 'Failed to start update')
}
}
const handleViewLogs = async () => {
try {
const response = await api.getSystemUpdateLogs()
if (!response) {
throw new Error('Failed to fetch update logs')
}
setLogs(response.logs)
setShowLogs(true)
} catch (err) {
setError('Failed to fetch update logs')
}
}
const checkVersionMutation = useMutation({
mutationKey: ['checkLatestVersion'],
mutationFn: () => api.checkLatestVersion(true),
onSuccess: (data) => {
if (data) {
setVersionInfo({
updateAvailable: data.updateAvailable,
latestVersion: data.latestVersion,
currentVersion: data.currentVersion,
})View on GitHub (pinned to 0bd1c6f4f9)
Solutions
- Check the actual HTTP status of the logs request in devtools
- Make the backend return {logs: []} instead of null/204 when no logs exist
- Preserve the original error in the catch instead of overwriting with the generic message
- Verify admin auth token is still valid when the modal is opened
Example fix
// before
const response = await api.getSystemUpdateLogs()
if (!response) {
throw new Error('Failed to fetch update logs')
}
// after
const response = await api.getSystemUpdateLogs()
const logs = response?.logs ?? []
setLogs(logs)
setShowLogs(true) Defensive patterns
Strategy: validation
Validate before calling
const exists = await api.getSystemUpdateLogs().catch(() => null)
if (exists?.logs) { setLogs(exists.logs) } else { setLogs([]) } Type guard
const hasLogs = (r: unknown): r is { logs: string[] } =>
Array.isArray((r as any)?.logs) Try / catch
try {
const r = await api.getSystemUpdateLogs()
setLogs(r?.logs ?? [])
setShowLogs(true)
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to fetch update logs')
} Prevention
- Backend should return {logs:[]} instead of null when no logs exist
- Preserve the original error message in the catch block
- Only offer View Logs after an update has actually run
When it happens
Trigger: GET of update logs returning empty body (e.g. no logs exist yet so backend returns null), 401/403 from auth middleware, or the log file unreadable on the server side.
Common situations: Opening logs before any update has run (log file missing), permissions on the log directory, or a stale admin token after session timeout.
Related errors
- Failed to fetch update status
- Failed to start update
- 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/abb126287ec60f0c.
Report an issue: GitHub.