{"id":"c436c43243b257b6","repo":"fastify/fastify","slug":"fst-err-route-handler-timeout-option-not-int","errorCode":"FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT","errorMessage":"'handlerTimeout' option must be an integer > 0. Got '%s'","messagePattern":"'handlerTimeout' option must be an integer > 0\\. Got '(.+?)'","errorType":"exception","errorClass":"TypeError","httpStatus":500,"severity":"error","filePath":"lib/route.js","lineNumber":631,"sourceCode":"}\n\nfunction validateSchemaBodyOption (method, path, schema) {\n  if (this[kSupportedHTTPMethods].bodyless.has(method) && schema?.body) {\n    throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path)\n  }\n}\n\nfunction validateBodyLimitOption (bodyLimit) {\n  if (bodyLimit === undefined) return\n  if (!Number.isInteger(bodyLimit) || bodyLimit <= 0) {\n    throw new FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT(bodyLimit)\n  }\n}\n\nfunction validateHandlerTimeoutOption (handlerTimeout) {\n  if (handlerTimeout === undefined) return\n  if (!Number.isInteger(handlerTimeout) || handlerTimeout <= 0) {\n    throw new FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT(handlerTimeout)\n  }\n}\n\nfunction validateLogLevelOption (logLevel, method, path, logger) {\n  if (logLevel == null || logLevel === '') return\n  if (logger?.levels?.values == null) return\n\n  if (typeof logLevel !== 'string' || logger.levels.values[logLevel] === undefined) {\n    throw new FST_ERR_ROUTE_LOG_LEVEL_INVALID(method, path, logLevel)\n  }\n}\n\nfunction runPreParsing (err, request, reply) {\n  if (reply.sent === true) return\n  if (err != null) {\n    reply[kReplyIsError] = true\n    reply.send(err)\n    return","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/fastify/fastify/blob/7299a57d3fdce7da49f2c6d19ba08dc673e53f22/lib/route.js#L613-L649","documentation":"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.","triggerScenarios":"fastify.get('/x', { handlerTimeout: '5000', handler }). handlerTimeout: 0, handlerTimeout: 2.5, or handlerTimeout loaded from config as a string.","commonSituations":"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).","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)."],"exampleFix":"// before\nfastify.get('/slow', { handlerTimeout: '5000' }, handler)\n\n// after\nfastify.get('/slow', { handlerTimeout: 5000 }, handler)","handlingStrategy":"validation","validationCode":"function resolveHandlerTimeout (raw) {\n  if (raw == null) return undefined\n  const n = Number(raw)\n  if (!Number.isInteger(n) || n <= 0) throw new TypeError(`handlerTimeout must be a positive integer ms, got ${raw}`)\n  return n\n}\nrouteOpts.handlerTimeout = resolveHandlerTimeout(config.timeout)","typeGuard":"const isPositiveIntMs = (v) => Number.isInteger(v) && v > 0","tryCatchPattern":null,"preventionTips":["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)."],"tags":["timeout","options","type-error","route-registration"],"analyzedSha":"7299a57d3fdce7da49f2c6d19ba08dc673e53f22","analyzedAt":"2026-08-03T17:43:01.300Z","schemaVersion":2}