linshenkx/prompt-optimizer · error

Health check failed

Error message

Health check failed

What it means

The /healthz route of the MCP server calls healthProvider.getHealthStatus(); if that promise rejects (or a non-Error is thrown), the catch block returns HTTP 503 with initialized:false and the error message, defaulting to the literal 'Health check failed' when the thrown value is not an Error instance.

Source

Thrown at packages/mcp-server/src/health.ts:29

export function buildHealthzResponse(healthStatus: MCPHealthStatus): {
  statusCode: number;
  body: MCPHealthStatus;
} {
  return {
    statusCode: isHealthyStatus(healthStatus) ? 200 : 503,
    body: healthStatus
  };
}

export function registerHealthzRoute(app: Express, healthProvider: HealthStatusProvider): void {
  app.get('/healthz', async (_req, res) => {
    try {
      const healthStatus = await healthProvider.getHealthStatus();
      const { statusCode, body } = buildHealthzResponse(healthStatus);
      res.status(statusCode).json(body);
    } catch (error) {
      res.status(503).json({
        initialized: false,
        services: {},
        error: error instanceof Error ? error.message : 'Health check failed'
      });
    }
  });
}

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Check the response body's error field and the server logs to see which underlying dependency failed (the generic message means a non-Error was thrown — log the raw value).
  2. Fix the underlying dependency (DB/storage connection, env config) so getHealthStatus resolves.
  3. Configure liveness/readiness probe thresholds to tolerate startup, or have getHealthStatus return degraded status objects instead of throwing.

Example fix

// before
res.status(503).json({ initialized: false, services: {}, error: error instanceof Error ? error.message : 'Health check failed' });
// after (also log the raw failure for diagnosis)
console.error('[healthz] non-Error failure:', error);
res.status(503).json({ initialized: false, services: {}, error: error instanceof Error ? error.message : String(error) });
Defensive patterns

Strategy: try-catch

Type guard

const isHealthzFailure = (body: unknown): body is { initialized: false; error: string } =>
  typeof body === 'object' && body !== null && (body as any).initialized === false

Try / catch

const res = await fetch(`${MCP_URL}/healthz`)
if (res.status === 503) {
  const body = await res.json().catch(() => null)
  log.warn('MCP unhealthy:', body?.error ?? 'unknown')
  // retry with backoff; if the message is the generic 'Health check failed', a non-Error was thrown server-side
}

Prevention

When it happens

Trigger: GET /healthz while a dependency checked by getHealthStatus is down or throws — e.g. storage/DB unreachable, a service not yet initialized — or when getHealthStatus itself has a bug and throws a string/non-Error value (which surfaces as the generic message).

Common situations: Kubernetes/container probes hitting /healthz before dependencies are ready; misconfigured connection strings causing getHealthStatus to reject; version changes to the health provider API throwing TypeError instead of structured status.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/416f78fe22e1edaa. Report an issue: GitHub.