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

  1. Check the actual HTTP status of the logs request in devtools
  2. Make the backend return {logs: []} instead of null/204 when no logs exist
  3. Preserve the original error in the catch instead of overwriting with the generic message
  4. 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

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


AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27). Data as JSON: /api/errors/abb126287ec60f0c. Report an issue: GitHub.