JuliusBrussee/caveman · error
--instance requires a private HTTPS origin (HTTP loopback…
Error message
--instance requires a private HTTPS origin (HTTP loopback is allowed for local development)
What it means
The `--instance` flag of the login command selects a private/self-hosted Caveman deployment against which to authenticate. For safety the URL must be a private HTTPS origin with no credentials, exactly the root path, no query string or hash, and must not equal the production API hostname; plain HTTP is only tolerated for loopback development. Anything failing secureLoginURL or these extra shape checks makes the CLI throw this error instead of opening a browser to a potentially hostile endpoint.
Solutions
- Pass only the bare origin over HTTPS: --instance https://caveman.internal.example (no path, query, hash, or credentials).
- For local development use HTTP loopback explicitly: --instance http://localhost:8787 or http://127.0.0.1:8787.
- Strip credentials from the URL and provide them another way, and remove any path/query/fragment from the value before retrying.
Example fix
// before caveman login --instance http://caveman.staging.example:8443/dashboard?tenant=acme // throws // after caveman login --instance https://caveman.staging.example
Defensive patterns
Strategy: validation
Validate before calling
function validateInstanceUrl(raw) {
const u = new URL(raw);
const isLoopbackHttp = u.protocol === "http:" && ["localhost", "127.0.0.1", "::1"].includes(u.hostname.replace(/\.$/, ""));
const ok = !u.username && !u.password && u.pathname === "/" && !u.search && !u.hash && (u.protocol === "https:" || isLoopbackHttp);
if (!ok) throw new Error("--instance must be a bare private HTTPS origin (HTTP loopback allowed).");
return u.origin;
} Try / catch
try {
caveman.login({ instance });
} catch (e) {
if (e instanceof Error && e.message.startsWith("--instance requires a private HTTPS origin")) {
console.error("Pass only the origin: https://host (or http://localhost:port for dev). No path/query/hash/credentials.");
} else throw e;
} Prevention
- Copy only the scheme+host(+port) of your private deployment into --instance, never the full browser URL.
- Use http://localhost:<port> explicitly for local development; anything else must be HTTPS.
- Never embed user:password credentials in the instance URL.
When it happens
Trigger: Running the login command with --instance set to: an http:// URL on a non-loopback host; a URL containing userinfo (user:pass@); a URL with a path other than "/" (e.g. https://caveman.internal/api), a query string (?x=1) or a fragment (#/dash); or the production API hostname passed explicitly.
Common situations: Pasting the full dashboard URL (with path/query) instead of just the origin; pointing --instance at a staging HTTP endpoint; including basic-auth credentials in the URL; forgetting that only loopback HTTP is allowed for local development.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- awscreds: AWS_CONTAINER_CREDENTIALS_FULL_URI is not a valid…
- githubapp: request path escaped configured host
- : every source must be HTTPS
- private device authorization returned an unsafe browser URL
- provider upstream URL must not include userinfo
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/faf3197641cbcea9.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:9587
if (noBrowser) commandUsage(usage);
noBrowser = true;
continue;
}
const flag = arg.split("=", 1)[0]!;
if (["--instance", "--base-url", "--gateway-url"].includes(flag)) {
const value = arg.includes("=") ? arg.slice(arg.indexOf("=") + 1) : argv[++index];
if (!value || value.startsWith("-") || values.has(flag)) commandUsage(usage);
values.set(flag, value);
continue;
}
commandUsage(usage);
}
const instance = values.get("--instance");
if (instance === undefined) return { noBrowser };
if (values.has("--base-url") || values.has("--gateway-url")) commandUsage(usage);
const url = new URL(instance);
if (!secureLoginURL(url) || url.pathname !== "/" || url.search || url.hash || url.hostname.replace(/\.$/, "") === new URL(PROD_API_URL).hostname) {
throw new Error("--instance requires a private HTTPS origin (HTTP loopback is allowed for local development)");
}
return { noBrowser, instance: url.origin };
}
function secureLoginURL(url: URL, allowLoopback = true): boolean {
return !url.username && !url.password && (url.protocol === "https:" ||
(allowLoopback && url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)));
}
function privateVerificationURL(code: Record<string, unknown>, instance: string): string {
if (typeof code.device_code !== "string" || !code.device_code || code.device_code.length > 4096 ||
typeof code.user_code !== "string" || !/^[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}$/.test(code.user_code) ||
typeof code.expires_in !== "number" || !Number.isFinite(code.expires_in) || code.expires_in <= 0 || code.expires_in > 3600 ||
(code.interval !== undefined && (typeof code.interval !== "number" || !Number.isFinite(code.interval) || code.interval < 0 || code.interval > 60))) {
throw new Error("private device authorization returned an invalid code response");
}
const value = code.verification_uri_complete ?? code.verification_uri;
if (typeof value !== "string") throw new Error("private device authorization omitted its browser URL");View on GitHub (pinned to 3ee70a1026)