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
- Inspect the wrapped platform error's stack — the real cause is in platform.lifecycle.restartServer(), not this line.
- Ensure no orphaned server process holds the port before restart (kill stale PID).
- If a CUDA backend was just downloaded, verify the download completed and the binary is executable before restarting.
- 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
- Preserve the original error via { cause: e } for debugging.
- Free the port / kill stale PIDs before restart to avoid the common spawn failure.
- Verify the server binary path exists, especially after a CUDA backend download.
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
- Failed to resolve save path from dialog
- HTTP ${res.status}
- System audio capture is only available in the desktop app.
- Native audio device routing is only available in the desktop
- captures.noTranscriptError
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/a6f3c736dd1fee21.
Report an issue: GitHub.