fastify/fastify · error · TypeError
FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT
FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT
Error message
'handlerTimeout' option must be an integer > 0. Got '%s'
What it means
Thrown by validateHandlerTimeoutOption (lib/route.js:631) when a route's handlerTimeout option is defined but is not a positive integer. handlerTimeout is the per-request wall-clock limit (milliseconds) after which Fastify aborts the request with FST_ERR_HANDLER_TIMEOUT (503). Strings, floats, zero, and negatives are rejected.
Source
Thrown at lib/route.js:631
}
function validateSchemaBodyOption (method, path, schema) {
if (this[kSupportedHTTPMethods].bodyless.has(method) && schema?.body) {
throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path)
}
}
function validateBodyLimitOption (bodyLimit) {
if (bodyLimit === undefined) return
if (!Number.isInteger(bodyLimit) || bodyLimit <= 0) {
throw new FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT(bodyLimit)
}
}
function validateHandlerTimeoutOption (handlerTimeout) {
if (handlerTimeout === undefined) return
if (!Number.isInteger(handlerTimeout) || handlerTimeout <= 0) {
throw new FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT(handlerTimeout)
}
}
function validateLogLevelOption (logLevel, method, path, logger) {
if (logLevel == null || logLevel === '') return
if (logger?.levels?.values == null) return
if (typeof logLevel !== 'string' || logger.levels.values[logLevel] === undefined) {
throw new FST_ERR_ROUTE_LOG_LEVEL_INVALID(method, path, logLevel)
}
}
function runPreParsing (err, request, reply) {
if (reply.sent === true) return
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
returnView on GitHub (pinned to 7299a57d3f)
Solutions
- Pass a positive integer in milliseconds: handlerTimeout: 5000.
- Coerce config strings: handlerTimeout: Number(opts.handlerTimeout) after an integer check.
- Omit the option to use the server-level handlerTimeout (default 0, meaning no limit).
Example fix
// before
fastify.get('/slow', { handlerTimeout: '5000' }, handler)
// after
fastify.get('/slow', { handlerTimeout: 5000 }, handler) Defensive patterns
Strategy: validation
Validate before calling
function resolveHandlerTimeout (raw) {
if (raw == null) return undefined
const n = Number(raw)
if (!Number.isInteger(n) || n <= 0) throw new TypeError(`handlerTimeout must be a positive integer ms, got ${raw}`)
return n
}
routeOpts.handlerTimeout = resolveHandlerTimeout(config.timeout) Type guard
const isPositiveIntMs = (v) => Number.isInteger(v) && v > 0
Prevention
- Always specify handlerTimeout in milliseconds as an integer.
- Coerce timeouts loaded from JSON/env to numbers explicitly.
- Omit the option to use the server default (0 = no limit).
When it happens
Trigger: fastify.get('/x', { handlerTimeout: '5000', handler }). handlerTimeout: 0, handlerTimeout: 2.5, or handlerTimeout loaded from config as a string.
Common situations: Reading the timeout from a JSON/YAML config or env var where it serializes as a string. Passing microseconds instead of milliseconds by mistake. Setting 0 expecting 'no timeout' (omit the option or use the server default 0 instead).
Related errors
- FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT
- FST_ERR_ROUTE_LOG_LEVEL_INVALID
- FST_ERR_ROUTE_OPTIONS_NOT_OBJ
- FST_ERR_ROUTE_METHOD_INVALID
- FST_ERR_ERROR_HANDLER_NOT_FN
AI-assisted analysis of fastify/fastify@7299a57d3f (2026-08-03).
Data as JSON: /data/errors/c436c43243b257b6.json.
Report an issue: GitHub.