jamiepine/voicebox · error · Error

e instanceof Error ? e.message : errorMessage

Error message

e instanceof Error ? e.message : errorMessage

What it means

Not a standalone error message but an error-wrapping pattern in restartServerWithPolling(). It awaits platform.lifecycle.restartServer(), starts health polling, and in the catch block rethrows `new Error(e instanceof Error ? e.message : errorMessage)` — preferring the underlying Error's message, otherwise falling back to the caller-supplied errorMessage string. The downstream handler surfaces whichever message wins.

Source

Thrown at app/src/components/ServerTab/GpuPage.tsx:286

          setTimeout(() => setRestartPhase('idle'), 2000);
        }
      } catch {
        // Server still down, keep polling
      }
    }, 1000);
  }, [queryClient, clearHealthPolling]);

  const restartServerWithPolling = useCallback(
    async (errorMessage: string) => {
      setRestartPhase('stopping');
      try {
        await platform.lifecycle.restartServer();
        setRestartPhase('waiting');
        startHealthPolling();
      } catch (e: unknown) {
        clearHealthPolling();
        setRestartPhase('idle');
        throw new Error(e instanceof Error ? e.message : errorMessage);
      }
    },
    [platform, startHealthPolling, clearHealthPolling],
  );

  const handleDownloadCuda = async () => {
    setError(null);
    try {
      await apiClient.downloadCudaBackend();
      setCudaStreaming(true);
      refetchCudaStatus();
    } catch (e: unknown) {
      const msg = e instanceof Error ? e.message : t('settings.gpu.errors.downloadStart');
      if (msg.includes('already downloaded')) {
        refetchCudaStatus();
      } else {
        setError(msg);
      }

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Inspect the wrapped platform error's stack — the real cause is in platform.lifecycle.restartServer(), not this line.
  2. Ensure no orphaned server process holds the port before restart (kill stale PID).
  3. If a CUDA backend was just downloaded, verify the download completed and the binary is executable before restarting.
  4. Preserve the original error via `{ cause: e }` instead of flattening to a message string for better debugging.

Example fix

// before
throw new Error(e instanceof Error ? e.message : errorMessage);
// after
throw new Error(e instanceof Error ? e.message : errorMessage, { cause: e });
Defensive patterns

Strategy: try-catch

Type guard

function isErrorWithMessage(e: unknown): e is Error {
  return e instanceof Error;
}

Try / catch

try {
  await platform.lifecycle.restartServer();
  setRestartPhase('waiting');
  startHealthPolling();
} catch (e: unknown) {
  clearHealthPolling();
  setRestartPhase('idle');
  throw new Error(e instanceof Error ? e.message : errorMessage, { cause: e });
}

Prevention

When it happens

Trigger: platform.lifecycle.restartServer() rejects (subprocess failed to stop/start, IPC error, server binary missing). A non-Error value was thrown inside the platform layer (rare; loses the fallback message). The health-polling setup itself throws synchronously.

Common situations: CUDA/backend download corrupted the server binary so it won't start. Port already in use by a stale process. Permissions error spawning the server. Tauri/IPC bridge returned a string error instead of an Error object.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/a6f3c736dd1fee21. Report an issue: GitHub.