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

  1. Pass an actual Date object with a valid value: new Date(Date.now() + 7*24*3600*1000)
  2. If you have a timestamp number, wrap it: new Date(timestamp)
  3. Check validity before calling: d instanceof Date && Number.isFinite(d.valueOf())
  4. 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

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


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/589bd7827614aa82. Report an issue: GitHub.