{"record":{"id":"f626f261ee7558a3","repo":"nextauthjs/next-auth","slug":"env-url-basepath-mismatch","errorCode":"env-url-basepath-mismatch","errorMessage":"env-url-basepath-mismatch","messagePattern":"env-url-basepath-mismatch","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/lib/utils/env.ts","lineNumber":89,"sourceCode":"}\n\nexport function createActionURL(\n  action: AuthAction,\n  protocol: string,\n  headers: Headers,\n  envObject: any,\n  config: Pick<AuthConfig, \"basePath\" | \"logger\">\n): URL {\n  const basePath = config?.basePath\n  const envUrl = envObject.AUTH_URL ?? envObject.NEXTAUTH_URL\n\n  let url: URL\n  if (envUrl) {\n    url = new URL(envUrl)\n    if (basePath && basePath !== \"/\" && url.pathname !== \"/\") {\n      if (url.pathname !== basePath) {\n        const logger = setLogger(config)\n        logger.warn(\"env-url-basepath-mismatch\")\n      }\n      url.pathname = \"/\"\n    }\n  } else {\n    const detectedHost = headers.get(\"x-forwarded-host\") ?? headers.get(\"host\")\n    const detectedProtocol =\n      headers.get(\"x-forwarded-proto\") ?? protocol ?? \"https\"\n    const _protocol = detectedProtocol.endsWith(\":\")\n      ? detectedProtocol\n      : detectedProtocol + \":\"\n\n    url = new URL(`${_protocol}//${detectedHost}`)\n  }\n\n  // remove trailing slash\n  const sanitizedUrl = url.toString().replace(/\\/$/, \"\")\n\n  if (basePath) {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/utils/env.ts#L71-L107","documentation":"createActionURL builds action URLs from AUTH_URL (envUrl) when present. If both AUTH_URL's pathname and the configured basePath exist and differ, the library warns 'env-url-basepath-mismatch' and resets url.pathname to '/' so the basePath from config wins. It indicates your environment URL and route prefix disagree, which can break redirects and callback URLs.","triggerScenarios":"Calling createActionURL (via url, signInURL, sessionUrl) when process.env.AUTH_URL has a non-'/' pathname that is not equal to config.basePath, e.g. AUTH_URL=https://x.com/other and basePath '/api/auth'.","commonSituations":"Deploy previews or proxies injecting a different AUTH_URL; copying AUTH_URL between services that use different route prefixes; forgetting to update AUTH_URL after renaming the auth route; monorepos where one app overrides AUTH_URL.","solutions":["Set AUTH_URL so its pathname equals config.basePath (or has no path at all)","Remove the basePath from AUTH_URL (use bare origin) and rely on config.basePath only","Ensure the build-time env (e.g. NEXTAUTH_URL/AUTH_URL baked at build) matches the runtime deployment","Filter logger.warn for this code if the mismatch is known and intentional"],"exampleFix":"// before\nAUTH_URL=https://app.example.com/legacy-auth\nbasePath: '/api/auth'\n// after\nAUTH_URL=https://app.example.com/api/auth\nbasePath: '/api/auth'","handlingStrategy":"validation","validationCode":"const envPath = new URL(process.env.AUTH_URL).pathname\nif (envPath !== '/' && envPath !== basePath) {\n  console.error(`AUTH_URL path ${envPath} mismatches basePath ${basePath}`)\n}","typeGuard":"function envUrlMatchesBasePath(u: string, basePath: string): boolean {\n  try { const p = new URL(u).pathname; return p === '/' || p === basePath } catch { return false }\n}","tryCatchPattern":null,"preventionTips":["Keep AUTH_URL and basePath sourced from a single config value","Validate env at app startup, not lazily at request time","Document env templates so deployments set origin-only AUTH_URL","Subscribe warn logs in production monitoring to catch drift"],"tags":["authjs","env","basepath","configuration"],"backgroundTag":"env-url-basepath-mismatch","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}