withastro/astro · error · TypeError

maxDuration must be a positive number

Error message

maxDuration must be a positive number

What it means

Thrown by the Vercel serverless adapter when `maxDuration` is a number but less than or equal to zero. Vercel function timeouts must be a positive integer representing seconds; zero or negative values are meaningless and rejected.

Source

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

	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 _routeToHeaders: RouteToHeaders | undefined = undefined;
	// Extra files to be merged with `includeFiles` during build
	const extraFilesToInclude: URL[] = [];
	// Secret used to verify that the caller is the astro-generated edge middleware and not a third-party
	const middlewareSecret = crypto.randomUUID();

	let _buildOutput: 'server' | 'static';

	let staticDir: URL | undefined;

View on GitHub (pinned to d081033d5f)

Solutions

  1. Use a positive integer: `maxDuration: 60`.
  2. Omit `maxDuration` entirely to keep Vercel's platform default.
  3. Validate and clamp: `const d = Number(raw); maxDuration: d > 0 ? d : undefined`.

Example fix

// before
vercel({ serverless: { maxDuration: 0 } })
// after
vercel({ serverless: { maxDuration: 60 } })
Defensive patterns

Strategy: validation

Validate before calling

function asPositiveMaxDuration(v: unknown): number | undefined {
  if (v == null) return undefined;
  const n = Number(v);
  if (!Number.isFinite(n) || n <= 0) throw new TypeError('maxDuration must be a positive number');
  return n;
}

Type guard

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

Prevention

When it happens

Trigger: Passing `maxDuration: 0`, a negative number, or a coerced NaN-from-empty-string that happens to be `<= 0`. Reaches this branch only after the type check passes.

Common situations: Setting `maxDuration` to 0 intending 'default' (use `undefined` instead). Math error computing the value. Env var resolving to '0'.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/aa475d6c3388555b. Report an issue: GitHub.