{"record":{"id":"7d7c7930f46ed9c4","repo":"withastro/astro","slug":"maxduration-must-be-a-number","errorCode":null,"errorMessage":"maxDuration must be a number","messagePattern":"maxDuration must be a number","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/integrations/vercel/src/index.ts","lineNumber":255,"sourceCode":"\twebAnalytics,\n\tincludeFiles: _includeFiles = [],\n\texcludeFiles: _excludeFiles = [],\n\timageService,\n\timagesConfig,\n\tdevImageService = 'sharp',\n\tmiddlewareMode,\n\tedgeMiddleware,\n\tmaxDuration,\n\tisr = false,\n\tskewProtection = process.env.VERCEL_SKEW_PROTECTION_ENABLED === '1',\n\tstaticHeaders = false,\n}: VercelServerlessConfig = {}): AstroIntegration {\n\t// Resolve middleware mode with backward compatibility\n\tconst resolvedMiddlewareMode = middlewareMode ?? (edgeMiddleware ? 'edge' : 'classic');\n\n\tif (maxDuration) {\n\t\tif (typeof maxDuration !== 'number') {\n\t\t\tthrow new TypeError(`maxDuration must be a number`, {\n\t\t\t\tcause: maxDuration,\n\t\t\t});\n\t\t}\n\t\tif (maxDuration <= 0) {\n\t\t\tthrow new TypeError(`maxDuration must be a positive number`, {\n\t\t\t\tcause: maxDuration,\n\t\t\t});\n\t\t}\n\t}\n\n\tlet _config: AstroConfig;\n\tlet _buildTempFolder: URL;\n\tlet _serverEntry: string;\n\tlet _middlewareEntryPoint: URL | undefined;\n\tlet _hasServerBuild = false;\n\tlet _routeToHeaders: RouteToHeaders | undefined = undefined;\n\t// Extra files to be merged with `includeFiles` during build\n\tconst extraFilesToInclude: URL[] = [];","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/withastro/astro/blob/3578d45d34226d63cff3d261c971c221de6794d2/packages/integrations/vercel/src/index.ts#L237-L273","documentation":"The Vercel adapter validates the maxDuration option (serverless function timeout in seconds) as soon as the integration is created: a truthy value that is not a number, such as a string pulled from an environment variable, throws a TypeError carrying the bad value as cause.","triggerScenarios":"Passing vercel({ maxDuration: '30' }), maxDuration: process.env.MAX_DURATION (always a string), or another non-number truthy value; a companion check also rejects numbers <= 0.","commonSituations":"Wiring the timeout from an env var or orchestrator config without converting types; config files authored as JSON/YAML where numbers arrive as strings.","solutions":["Pass a plain positive number: maxDuration: 30","Convert env strings: maxDuration: Number(process.env.MAX_DURATION)","Guard optional values so undefined (option omitted) is passed instead of 'undefined' or NaN"],"exampleFix":"// before\nvercel({ maxDuration: process.env.MAX_DURATION })\n// after\nvercel({ maxDuration: Number(process.env.MAX_DURATION) })","handlingStrategy":"type-guard","validationCode":"const raw = process.env.MAX_DURATION;\nconst maxDuration = raw === undefined ? undefined : Number(raw);\nif (maxDuration !== undefined && (!Number.isFinite(maxDuration) || maxDuration <= 0)) {\n  throw new Error('MAX_DURATION must be a positive number of seconds');\n}\nvercel({ maxDuration })","typeGuard":"function isPositiveNumber(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v > 0;\n}","tryCatchPattern":null,"preventionTips":["Coerce env-sourced options with Number() before passing them to the adapter","Keep numeric adapter options numeric in config files (avoid quoted YAML values)","Validate the whole adapter options object in a preflight check"],"tags":["vercel","config","type-error","max-duration"],"backgroundTag":"option-type-mismatch","analyzedSha":"3578d45d34226d63cff3d261c971c221de6794d2","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}