tinyhumansai/openhuman · error

[app-update] hook: unknown status payload

Error message

[app-update] hook: unknown status payload

What it means

Defensive default in parseStatusPayload(): an `app-update:status` event arrived from the Rust side carrying a phase string not in the known set (checking/downloading/...). Rather than silently ignoring an unrecognized payload, the mapper coerces it to the 'error' phase so the UI surfaces the mismatch; the log names the offending raw value.

Source

Thrown at app/src/hooks/useAppUpdate.ts:125

/** A short grace before the auto-download fires, so the UI can show the
 *  fact that an update was *detected* (briefly) before going into "downloading"
 *  state. Cosmetic, not load-bearing. */
const AUTO_DOWNLOAD_GRACE_MS = 1_000;

/**
 * Translate a raw `app-update:status` payload into our phase enum, defaulting
 * to `error` for any unrecognized string so we don't silently swallow a bad
 * payload from the Rust side.
 */
function parseStatusPayload(raw: unknown): AppUpdatePhase {
  if (raw === 'checking') return 'checking';
  if (raw === 'downloading') return 'downloading';
  if (raw === 'ready_to_install') return 'ready_to_install';
  if (raw === 'installing') return 'installing';
  if (raw === 'restarting') return 'restarting';
  if (raw === 'up_to_date') return 'up_to_date';
  if (raw === 'error') return 'error';
  console.warn('[app-update] hook: unknown status payload', raw);
  return 'error';
}

export function useAppUpdate(options: UseAppUpdateOptions = {}): UseAppUpdateResult {
  const {
    autoCheck = true,
    initialCheckDelayMs = DEFAULT_INITIAL_DELAY_MS,
    recheckIntervalMs = DEFAULT_RECHECK_INTERVAL_MS,
    autoDownload = true,
  } = options;

  const [phase, setPhase] = useState<AppUpdatePhase>('idle');
  const [info, setInfo] = useState<AppUpdateInfo | null>(null);
  const [bytesDownloaded, setBytesDownloaded] = useState(0);
  const [totalBytes, setTotalBytes] = useState<number | null>(null);
  const [error, setError] = useState<string | null>(null);

  // Refs to keep callbacks stable + survive React 18 strict-mode double-invoke.

View on GitHub (pinned to 7491200858)

Solutions

  1. Compare the raw payload in the log with the Rust-side status enum to find the added/renamed variant
  2. Extend the TS union and parser when the Rust side legitimately adds a status
  3. Treat unknown payloads as no-op instead of error if stale-version skew is expected
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at app/src/hooks/useAppUpdate.ts:125 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/ac9da4f160fb10bb. Report an issue: GitHub.