nextauthjs/next-auth · error · TypeError

option domain is invalid: ${options.domain}

Error message

option domain is invalid: ${options.domain}

What it means

serialize() validates the optional `domain` option against domainValueRegExp before appending `; Domain=` to the Set-Cookie string. If the value is present but not a syntactically valid domain attribute (e.g. contains illegal characters, spaces, or an invalid form), a TypeError is thrown immediately. This is a fail-fast guard so malformed cookie attributes never reach the browser.

Source

Thrown at packages/core/src/lib/vendored/cookie.ts:284

  if (!cookieValueRegExp.test(value)) {
    throw new TypeError(`argument val is invalid: ${val}`)
  }

  let str = name + "=" + value
  if (!options) return str

  if (options.maxAge !== undefined) {
    if (!Number.isInteger(options.maxAge)) {
      throw new TypeError(`option maxAge is invalid: ${options.maxAge}`)
    }

    str += "; Max-Age=" + options.maxAge
  }

  if (options.domain) {
    if (!domainValueRegExp.test(options.domain)) {
      throw new TypeError(`option domain is invalid: ${options.domain}`)
    }

    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())
    ) {

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Pass only the bare hostname, e.g. domain: 'example.com' (leading dot is allowed but unnecessary for host-only matching)
  2. Strip protocol/path/port: new URL(configuredDomain).hostname
  3. Validate with a regex before calling serialize
  4. If the domain is dynamic/user-supplied, reject invalid values upstream instead of letting serialize throw

Example fix

// before
serialize('sid', val, { domain: process.env.COOKIE_DOMAIN }) // 'https://example.com'
// after
const { hostname } = new URL(process.env.COOKIE_DOMAIN)
serialize('sid', val, { domain: hostname })
Defensive patterns

Strategy: validation

Validate before calling

function isValidCookieDomain(d) {
  return typeof d === 'string' && /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/.test(d.replace(/^\./, ''))
}
if (opts.domain && !isValidCookieDomain(opts.domain)) throw new TypeError(`option domain is invalid: ${opts.domain}`)

Type guard

function isCookieDomain(v: unknown): v is string {
  return typeof v === 'string' && v.length > 0 && !/[^a-zA-Z0-9.\-]/.test(v)
}

Try / catch

let cookie
try {
  cookie = serialize('sid', val, { domain })
} catch (err) {
  if (err instanceof TypeError && err.message.startsWith('option domain is invalid')) {
    throw new ConfigError(`Bad COOKIE_DOMAIN '${domain}' — use a bare hostname, not a URL`)
  }
  throw err
}

Prevention

When it happens

Trigger: Calling serialize(name, val, { domain: 'not a domain!' }) or any domain containing characters outside the allowed domain-value pattern — e.g. trailing dots/slashes, underscores, spaces, full URLs like 'https://example.com', or an empty-but-truthy invalid string.

Common situations: Reading the domain from an env var or config that holds a full URL instead of a bare hostname; concatenating a port ('example.com:3000' — ports are not allowed in cookie domains); user-supplied input passed through unvalidated; typos like 'exam ple.com'.

Related errors


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