withastro/astro · error · TypeError

maxDuration must be a number

Error message

maxDuration must be a number

What it means

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.

Solutions

  1. Pass a plain positive number: maxDuration: 30
  2. Convert env strings: maxDuration: Number(process.env.MAX_DURATION)
  3. Guard optional values so undefined (option omitted) is passed instead of 'undefined' or NaN

Example fix

// before
vercel({ maxDuration: process.env.MAX_DURATION })
// after
vercel({ maxDuration: Number(process.env.MAX_DURATION) })
Defensive patterns

Strategy: type-guard

Validate before calling

const raw = process.env.MAX_DURATION;
const maxDuration = raw === undefined ? undefined : Number(raw);
if (maxDuration !== undefined && (!Number.isFinite(maxDuration) || maxDuration <= 0)) {
  throw new Error('MAX_DURATION must be a positive number of seconds');
}
vercel({ maxDuration })

Type guard

function isPositiveNumber(v: unknown): v is number {
  return typeof v === 'number' && Number.isFinite(v) && v > 0;
}

Prevention

When it happens

Trigger: 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.

Common situations: Wiring the timeout from an env var or orchestrator config without converting types; config files authored as JSON/YAML where numbers arrive as strings.

Related errors


AI-assisted analysis of withastro/astro@3578d45d34 (2026-08-18). Data as JSON: /api/errors/7d7c7930f46ed9c4. Report an issue: GitHub.

Appendix: source

Thrown at packages/integrations/vercel/src/index.ts:255

	webAnalytics,
	includeFiles: _includeFiles = [],
	excludeFiles: _excludeFiles = [],
	imageService,
	imagesConfig,
	devImageService = 'sharp',
	middlewareMode,
	edgeMiddleware,
	maxDuration,
	isr = false,
	skewProtection = process.env.VERCEL_SKEW_PROTECTION_ENABLED === '1',
	staticHeaders = false,
}: VercelServerlessConfig = {}): AstroIntegration {
	// Resolve middleware mode with backward compatibility
	const resolvedMiddlewareMode = middlewareMode ?? (edgeMiddleware ? 'edge' : 'classic');

	if (maxDuration) {
		if (typeof maxDuration !== 'number') {
			throw new TypeError(`maxDuration must be a number`, {
				cause: maxDuration,
			});
		}
		if (maxDuration <= 0) {
			throw new TypeError(`maxDuration must be a positive number`, {
				cause: maxDuration,
			});
		}
	}

	let _config: AstroConfig;
	let _buildTempFolder: URL;
	let _serverEntry: string;
	let _middlewareEntryPoint: URL | undefined;
	let _hasServerBuild = false;
	let _routeToHeaders: RouteToHeaders | undefined = undefined;
	// Extra files to be merged with `includeFiles` during build
	const extraFilesToInclude: URL[] = [];

View on GitHub (pinned to 3578d45d34)