different-ai/openwork · error
Timed out waiting for server health
Error message
Timed out waiting for server health
What it means
waitForHealthy polls the opencode server health endpoint until it responds or a deadline expires. Each poll failure's message is retained in lastError; when the loop exhausts, it throws the last seen error, or "Timed out waiting for server health" if none was captured. Indicates the server never became reachable in time.
Solutions
- Check server stderr/stdout logs captured during spawn for a startup crash.
- Verify the configured port/host matches where the server actually listens.
- Increase the health-wait deadline or poll interval for slower machines.
- Confirm the server binary runs standalone (`opencode serve`) to isolate spawn problems.
Example fix
// before: fixed budget
await waitForHealthy(server, { timeoutMs: 5000 });
// after: larger budget on cold start
await waitForHealthy(server, { timeoutMs: process.env.CI ? 30000 : 10000 }); Defensive patterns
Strategy: retry
Validate before calling
// probe before relying on waitForHealthy's deadline
const reachable = await fetch(`http://${host}:${port}/health`).then(r => r.ok).catch(() => false);
if (!reachable) console.warn("Server port not reachable; startup may have failed."); Try / catch
try {
await waitForHealthy(server, { timeoutMs: 15000 });
} catch (err) {
if (err instanceof Error && /health|Unknown error/i.test(err.message)) {
// inspect spawned process logs and exit code before giving up
const logs = server.getStderr?.() ?? "";
throw new Error(`Server failed to become healthy: ${err.message}\nstderr: ${logs.slice(-500)}`);
}
throw err;
} Prevention
- Verify the server binary starts standalone before wiring health waits.
- Allocate longer health budgets in CI and on cold machine starts.
- Check for port conflicts before spawning the server.
- Capture and surface server stderr alongside the timeout error.
When it happens
Trigger: Spawning/starting the local opencode server and polling health until the deadline passes: server binary failed to start, wrong port, crash on boot, or startup slower than the wait budget.
Common situations: Missing/incompatible opencode server binary, port already in use or firewalled, machine under load slowing startup, first install downloading dependencies while health polls expire.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Connection lost
- agent_context_diagnostics_request_timed_out
- Connection closed before the tool response completed
- MCP_SHUTDOWN_FAILED
- OpenWork server did not become ready after activation.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/8edd4411b9d1e229.
Report an issue: GitHub.
Appendix: source
Thrown at apps/app/src/app/lib/opencode.ts:353
const pollMs = options?.pollMs ?? 250;
const start = Date.now();
let lastError: string | null = null;
while (Date.now() - start < timeoutMs) {
try {
const health = unwrap(await client.global.health());
if (health.healthy) {
return health;
}
lastError = "Server reported unhealthy";
} catch (error) {
lastError = error instanceof Error ? error.message : "Unknown error";
}
await new Promise((resolve) => setTimeout(resolve, pollMs));
}
throw new Error(lastError ?? "Timed out waiting for server health");
}
View on GitHub (pinned to 2b7df46e8a)