mastra-ai/mastra · error · RangeError
server.drainTimeout must be a finite number between 0 and 21
Error message
server.drainTimeout must be a finite number between 0 and 2147483647 milliseconds
What it means
createNodeServer validates the optional serverOptions.drainTimeout before binding. Unless shutdown-signal handling is disabled (handleShutdownSignals === false), the value must be a finite number between 0 and 2147483647 ms (the max for Node setTimeout); otherwise a RangeError is thrown. The default is 5000 ms.
Source
Thrown at packages/deployer/src/server/index.ts:580
// Attach injectWebSocket to app for backwards compatibility
// Consumers can use app directly, and optionally call app.injectWebSocket(server) for browser streaming
(app as any).injectWebSocket = browserStreamSetup?.injectWebSocket;
return app;
}
export async function createNodeServer(mastra: Mastra, options: ServerBundleOptions = { tools: {} }) {
const app = await createHonoServer(mastra, options);
const injectWebSocket = (app as any).injectWebSocket;
const serverOptions = mastra.getServer();
const apiPrefix = serverOptions?.apiPrefix ?? '/api';
const drainTimeoutMs = serverOptions?.drainTimeout ?? 5000;
if (
serverOptions?.handleShutdownSignals !== false &&
(!Number.isFinite(drainTimeoutMs) || drainTimeoutMs < 0 || drainTimeoutMs > 2_147_483_647)
) {
throw new RangeError('server.drainTimeout must be a finite number between 0 and 2147483647 milliseconds');
}
const key =
serverOptions?.https?.key ??
(process.env.MASTRA_HTTPS_KEY ? Buffer.from(process.env.MASTRA_HTTPS_KEY, 'base64') : undefined);
const cert =
serverOptions?.https?.cert ??
(process.env.MASTRA_HTTPS_CERT ? Buffer.from(process.env.MASTRA_HTTPS_CERT, 'base64') : undefined);
const isHttpsEnabled = Boolean(key && cert);
const bindHost = serverOptions?.host ?? process.env.MASTRA_HOST;
const host = bindHost ?? 'localhost';
const port = serverOptions?.port ?? (Number(process.env.PORT) || 4111);
const protocol = isHttpsEnabled ? 'https' : 'http';
const studioHost = serverOptions?.studioHost ?? host;
const studioProtocol = serverOptions?.studioProtocol ?? protocol;
const studioPort = serverOptions?.studioPort ?? port;
View on GitHub (pinned to 75dd419e61)
Solutions
- Set drainTimeout to a finite number of milliseconds within 0..2147483647 (e.g. 5000).
- If loading from env, coerce explicitly: Number(process.env.DRAIN_TIMEOUT) and validate Number.isFinite before passing.
- Set handleShutdownSignals: false only if you manage graceful shutdown yourself, which skips this validation.
Example fix
// before
{ drainTimeout: '30s' }
// after
{ drainTimeout: 30000 } Defensive patterns
Strategy: validation
Validate before calling
function parseDrainTimeout(raw) {
const n = typeof raw === 'number' ? raw : Number(raw);
if (!Number.isFinite(n) || n < 0 || n > 2_147_483_647) throw new RangeError(`drainTimeout must be 0..2147483647 ms, got ${raw}`);
return n;
}
const drainTimeout = parseDrainTimeout(process.env.DRAIN_TIMEOUT ?? 5000); Type guard
function isValidDrainTimeout(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 2_147_483_647;
} Try / catch
try {
const server = await createNodeServer(mastra, { drainTimeout });
} catch (e) {
if (e instanceof RangeError && /drainTimeout/.test(e.message)) {
console.error('Fix server.drainTimeout: finite milliseconds in [0, 2147483647].');
}
throw e;
} Prevention
- Coerce and validate numeric config from env/JSON before passing it to server options
- Remember the unit is milliseconds (5000 = 5s)
- Only set handleShutdownSignals: false if you own graceful shutdown
When it happens
Trigger: Passing serverOptions.drainTimeout as NaN, Infinity, a negative number, a value > 2147483647, or a non-number (e.g. a string parsed from config) when creating the node server with shutdown signal handling enabled.
Common situations: Reading drainTimeout from env/config as a string ('5000') or from JSON as null; arithmetic producing NaN; setting an absurdly large value believing the unit is seconds instead of milliseconds.
Understand the failure class
Background: "Invalid configuration value" and "Unsupported/Unknown setting value" errors: why libraries reject your config strings, numbers, and types — this error's family across 30 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- AcpAgent does not support resuming suspended generate calls
- ACP prompt stopped before completing: ${response.stopReason}
- Google RBAC roleMapping is required.
- Cookie password must be at least 32 characters. Set OKTA_COO
- heartbeatMs must be a finite number no greater than ${MAX_TI
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2951d51f37fed395.
Report an issue: GitHub.