vercel/next.js · error · Error

Using a self signed certificate is only supported with `next

Error message

Using a self signed certificate is only supported with `next dev`.

What it means

Thrown by start-server when the experimental self-signed HTTPS certificate option is enabled but the server is not in development mode. Self-signed certificate generation is a dev-only convenience and is intentionally blocked for production starts.

Source

Thrown at packages/next/src/server/lib/start-server.ts:236

  }
  let upgradeHandler: WorkerUpgradeHandler = async (
    req,
    socket,
    head
  ): Promise<void> => {
    if (handlersPromise) {
      await handlersPromise
      return upgradeHandler(req, socket, head)
    }
    throw new Error('Invariant upgrade handler was not setup')
  }

  let nextServer: NextServer | undefined
  let devMemoryThresholdRestart = true

  // setup server listener as fast as possible
  if (selfSignedCertificate && !isDev) {
    throw new Error(
      'Using a self signed certificate is only supported with `next dev`.'
    )
  }

  async function requestListener(req: IncomingMessage, res: ServerResponse) {
    try {
      if (handlersPromise) {
        await handlersPromise
        handlersPromise = undefined
      }
      await requestHandler(req, res)
    } catch (err) {
      res.statusCode = 500
      res.end('Internal Server Error')
      Log.error(`Failed to handle request for ${req.url}`)
      console.error(err)
    } finally {
      const memoryRestartStats = getMemoryRestartStats(

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Use `next dev` when you need the self-signed certificate feature.
  2. Remove or guard the experimental.https/selfSignedCertificate config for production builds.
  3. For production HTTPS, terminate TLS at a reverse proxy/load balancer with a real certificate instead.

Example fix

// before: HTTPS config always on
module.exports = {
  experimental: { https: { selfSigned: true } },
}

// after: enable only in dev
module.exports = process.env.NODE_ENV === 'development'
  ? { experimental: { https: { selfSigned: true } } }
  : {}
Defensive patterns

Strategy: validation

Validate before calling

const isDev = process.env.NODE_ENV === 'development'
if (config.experimental?.https && !isDev) {
  throw new Error('self-signed cert is dev-only; remove it for production')
}

Type guard

function canUseSelfSignedCert(isDev: boolean, config: any): boolean {
  return !config?.experimental?.https || isDev
}

Try / catch

null

Prevention

When it happens

Trigger: next.config.js enables experimental.https (or selfSignedCertificate) and the app is started with `next start` (production) instead of `next dev`. The guard `if (selfSignedCertificate && !isDev)` triggers.

Common situations: Keeping the dev HTTPS config in next.config.js when deploying, or a custom server script that calls startServer with isDev:false while the config still requests HTTPS.

Understand the failure class

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/45f5a998ad8e0576. Report an issue: GitHub.