gethomepage/homepage · critical · Error

HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute

Error message

HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute HTTP(S) URL.

What it means

Thrown when NEXTAUTH_URL / HOMEPAGE_EXTERNAL_URL is present but `new URL(...)` rejects it, meaning the value is not a parseable absolute URL. Homepage refuses to proceed because NextAuth needs a valid absolute URL for redirects and JWT signing.

Source

Thrown at src/pages/api/auth/[...nextauth].js:44

if (!process.env.NEXTAUTH_URL && homepageExternalUrl) {
  process.env.NEXTAUTH_URL = homepageExternalUrl;
}

const defaultScope = process.env.HOMEPAGE_OIDC_SCOPE || "openid email profile";
const cleanedIssuer = issuer ? issuer.replace(/\/+$/, "") : issuer;
const hasOidcConfig = Boolean(issuer && clientId && clientSecret);
const hasAnyOidcConfig = Boolean(issuer || clientId || clientSecret);
let parsedAuthUrl;

if (authEnabled) {
  if (!process.env.NEXTAUTH_URL) {
    throw new Error("Homepage auth is enabled but HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) is missing.");
  }

  try {
    parsedAuthUrl = new URL(process.env.NEXTAUTH_URL);
  } catch {
    throw new Error("HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute HTTP(S) URL.");
  }

  if (
    !["http:", "https:"].includes(parsedAuthUrl.protocol) ||
    parsedAuthUrl.username ||
    parsedAuthUrl.password ||
    parsedAuthUrl.search ||
    parsedAuthUrl.hash
  ) {
    throw new Error(
      "HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute HTTP(S) URL without credentials, query, or fragment.",
    );
  }

  if (hasOidcConfig) {
    if (!process.env.NEXTAUTH_SECRET) {
      throw new Error("OIDC auth is enabled but required settings are missing.");
    }

View on GitHub (pinned to b6dca1ae03)

Solutions

  1. Set the URL with an explicit https:// (or http://) scheme and a host: https://home.example.com.
  2. Check for leading/trailing whitespace or quotes in the env value, especially in docker-compose / Kubernetes secrets.
  3. Verify the variable actually feeding NEXTAUTH_URL/HOMEPAGE_EXTERNAL_URL — print it once in a debug shell inside the container.
  4. If testing locally without TLS, use http://127.0.0.1:3000 (still must be absolute).

Example fix

// before
HOMEPAGE_EXTERNAL_URL=home.example.com

// after
HOMEPAGE_EXTERNAL_URL=https://home.example.com
Defensive patterns

Strategy: validation

Validate before calling

function assertAbsoluteUrl(raw, name = 'URL') {
  let u;
  try { u = new URL(raw); } catch { throw new Error(`${name} is not a valid absolute URL: ${raw}`); }
  return u;
}
// before app boot:
if (process.env.HOMEPAGE_AUTH_ENABLED === 'true') {
  assertAbsoluteUrl(process.env.NEXTAUTH_URL || process.env.HOMEPAGE_EXTERNAL_URL, 'NEXTAUTH_URL');
}

Type guard

function isValidAbsoluteUrl(v) {
  if (typeof v !== 'string' || !v.trim()) return false;
  try { new URL(v); return true; } catch { return false; }
}

Prevention

When it happens

Trigger: authEnabled is true, NEXTAUTH_URL is truthy, but its value cannot be parsed by the WHATWG URL constructor (e.g. 'home.example.com', 'home', '//home', 'ftp x', or an empty-ish malformed string). The `catch {}` block around `new URL(...)` re-throws this message.

Common situations: User omitted the scheme (wrote 'home.example.com' instead of 'https://home.example.com'); trailing copy-paste introduced a space; value bound to a wrong env var; Docker env interpolation produced an empty/garbage string.

Related errors


AI-assisted analysis of gethomepage/homepage@b6dca1ae03 (2026-08-13). Data as JSON: /api/errors/10909bfa181542f9. Report an issue: GitHub.