nextauthjs/next-auth · error · TypeError
option expires is invalid: ${options.expires}
Error message
option expires is invalid: ${options.expires} What it means
serialize() requires the `expires` option, when provided, to be a real Date object with a finite time value. If it is not a Date instance (isDate fails) or its valueOf() is NaN/Infinity (an Invalid Date), a TypeError is thrown. This guards against invalid dates silently producing 'Expires=Invalid Date' in the header.
Source
Thrown at packages/core/src/lib/vendored/cookie.ts:303
}
str += "; Domain=" + options.domain
}
if (options.path) {
if (!pathValueRegExp.test(options.path)) {
throw new TypeError(`option path is invalid: ${options.path}`)
}
str += "; Path=" + options.path
}
if (options.expires) {
if (
!isDate(options.expires) ||
!Number.isFinite(options.expires.valueOf())
) {
throw new TypeError(`option expires is invalid: ${options.expires}`)
}
str += "; Expires=" + options.expires.toUTCString()
}
if (options.httpOnly) {
str += "; HttpOnly"
}
if (options.secure) {
str += "; Secure"
}
if (options.partitioned) {
str += "; Partitioned"
}
if (options.priority) {View on GitHub (pinned to a1a16a5a77)
Solutions
- Pass an actual Date object with a valid value: new Date(Date.now() + 7*24*3600*1000)
- If you have a timestamp number, wrap it: new Date(timestamp)
- Check validity before calling: d instanceof Date && Number.isFinite(d.valueOf())
- If the value may be a string, parse it first and verify it is not Invalid Date
Example fix
// before
serialize('sid', val, { expires: payload.exp }) // number from JWT
// after
serialize('sid', val, { expires: new Date(payload.exp * 1000) }) Defensive patterns
Strategy: type-guard
Validate before calling
function isValidExpires(v) {
return v instanceof Date && Number.isFinite(v.valueOf())
}
if (opts.expires && !isValidExpires(opts.expires)) throw new TypeError(`option expires is invalid: ${opts.expires}`) Type guard
function isFiniteDate(v: unknown): v is Date {
return v instanceof Date && Number.isFinite(v.valueOf())
} Try / catch
let cookie
try {
cookie = serialize('sid', val, { expires })
} catch (err) {
if (err instanceof TypeError && err.message.startsWith('option expires is invalid')) {
throw new SessionError(`Invalid expiry ${String(expires)} — pass a valid Date`)
}
throw err
} Prevention
- Always construct Date objects from numeric timestamps, not raw strings
- After new Date(x), assert Number.isFinite(d.valueOf()) before using it
- Remember JSON serialization turns Dates into strings — re-parse on ingest
- Compute expiries with explicit numeric TTLs to avoid NaN from undefined variables
When it happens
Trigger: Passing expires: new Date('not-a-date') (Invalid Date); passing a date string like '2026-01-01' instead of a Date; passing a number timestamp; passing null/undefined-like truthy junk; a Date computed from bad input such as new Date(undefined).
Common situations: Parsing user-supplied expiry dates without validation; jwt/session libs returning string timestamps; JSON round-tripping Dates (they come back as strings); arithmetic mistakes that yield NaN (e.g. new Date(Date.now() + ttl) where ttl is undefined).
Related errors
- option domain is invalid: ${options.domain}
- option path is invalid: ${options.path}
- option priority is invalid: ${options.priority}
- option sameSite is invalid: ${options.sameSite}
- argument name is invalid: ${name}
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/589bd7827614aa82.
Report an issue: GitHub.