mastra-ai/mastra · error

Mastra server did not become healthy at ${url}${healthCheckP

Error message

Mastra server did not become healthy at ${url}${healthCheckPath} within ${healthCheckTimeoutMs}ms.

What it means

During deployToSandbox, after installing and starting the Mastra server inside the sandbox, the engine polls the health endpoint until timeout. If waitForHealthy never succeeds within healthCheckTimeoutMs, this error is thrown, including the server log tail (or a note that no log was captured) for diagnosis.

Source

Thrown at deployers/sandbox/src/engine.ts:152

  // 4. Write the launch script and start the new server (the previous one was
  // stopped before extraction).
  const launchScript = buildLaunchScript({ remoteDir, port, env: mergedEnv });
  await uploadFile(sandbox, `${remoteDir}/${SERVER_SCRIPT}`, Buffer.from(launchScript));
  await runInSandbox(sandbox, `chmod 700 ${shellQuote(`${remoteDir}/${SERVER_SCRIPT}`)}`);

  logger.info('Starting Mastra server...');
  await launchServer(sandbox, remoteDir);

  // 5. Wait for the server to answer on its public URL.
  const healthy = await waitForHealthy(url, {
    path: healthCheckPath,
    timeoutMs: healthCheckTimeoutMs,
    intervalMs: healthCheckIntervalMs,
  });
  if (!healthy) {
    const log = await tailServerLog(sandbox, remoteDir).catch(() => '');
    throw new Error(
      `Mastra server did not become healthy at ${url}${healthCheckPath} within ${healthCheckTimeoutMs}ms.` +
        (log ? `\n\nServer log:\n${log}` : '\n\n(no server log output captured)'),
    );
  }

  const info = await getInfoSafe(sandbox);

  return {
    url,
    sandboxId: info?.id ?? sandbox.id,
    expiresAt: info?.timeoutAt,
    stop: async () => {
      await sandbox.stop?.();
    },
    destroy: async () => {
      await sandbox.destroy?.();
    },
    logs: (lines?: number) => tailServerLog(sandbox, remoteDir, lines),

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the 'Server log:' section in the error for the root cause
  2. Increase healthCheckTimeoutMs (and/or intervalMs) for slower environments
  3. Verify healthCheckPath and PORT match the server's actual configuration
  4. Ensure required env vars are exported in the launch script/env passed to the deploy
  5. Check the install step succeeded (npm install --omit=dev output)

Example fix

// before
await deployToSandbox(sandbox, { healthCheckTimeoutMs: 30_000 });
// after
await deployToSandbox(sandbox, {
  healthCheckTimeoutMs: 180_000,
  env: { DATABASE_URL: process.env.DATABASE_URL },
});
Defensive patterns

Strategy: retry

Validate before calling

// preflight: ensure install/start inputs are sane before the timed health wait
if (!existsSync(join(dir, 'index.mjs'))) throw new Error('build first');
if (!env.PORT) throw new Error('PORT must be provided in env');

Try / catch

try {
  await deployToSandbox(sandbox, { healthCheckTimeoutMs: 180_000 });
} catch (err) {
  if (String(err).includes('did not become healthy')) {
    const log = String(err).split('Server log:')[1] ?? '(no log)';
    console.error('boot failure:', log);
  } else throw err;
}

Prevention

When it happens

Trigger: deployToSandbox starts the server and waitForHealthy({ path: healthCheckPath, timeoutMs, intervalMs }) exhausts its timeout while the server is down, misconfigured, or still booting.

Common situations: Install step failed silently (broken dependencies), server crashes on missing env/secrets, healthCheckPath mismatch, port/host misconfiguration, slow startup exceeding the timeout, provider network restrictions blocking health check traffic.

Understand the failure class

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/7d37cab5c6a3778d. Report an issue: GitHub.