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
- Set the URL with an explicit https:// (or http://) scheme and a host: https://home.example.com.
- Check for leading/trailing whitespace or quotes in the env value, especially in docker-compose / Kubernetes secrets.
- Verify the variable actually feeding NEXTAUTH_URL/HOMEPAGE_EXTERNAL_URL — print it once in a debug shell inside the container.
- 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
- Always include the scheme (https://) when setting URL env.
- Lint env files for scheme-less URLs.
- Use a docker compose `${VAR:?error}` assertion to fail at container start.
- Document the expected URL shape next to the variable in your env template.
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
- HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute
- Homepage auth is enabled but HOMEPAGE_EXTERNAL_URL (or NEXTA
- OIDC auth is enabled but required settings are missing.
- Password auth is enabled but required settings are missing.
- HOMEPAGE_AUTH_SECRET (or NEXTAUTH_SECRET) must be at least $
AI-assisted analysis of gethomepage/homepage@b6dca1ae03 (2026-08-13).
Data as JSON: /api/errors/10909bfa181542f9.
Report an issue: GitHub.