can1357/oh-my-pi · error · SearchProviderError

GOOGLE_GEMINI_BASE_URL must be a valid absolute URL

Error message

GOOGLE_GEMINI_BASE_URL must be a valid absolute URL

What it means

resolveGeminiDeveloperEndpoint() reads GOOGLE_GEMINI_BASE_URL (defaulting to the Gemini Developer API host) and parses it with `new URL()`. If the value is set but is not a parsable absolute URL — missing scheme entirely, or garbage text — it throws this SearchProviderError with status 400 before any network request is made. This guard also runs during isAvailable(), so it can surface at startup/availability checks, not only at search time.

Source

Thrown at packages/coding-agent/src/web/search/providers/gemini.ts:56

	if (envModel) return envModel;
	const model = configuredModel?.trim();
	return model || DEFAULT_MODEL;
}

interface GeminiDeveloperEndpoint {
	url: string;
	authProvider: typeof DEVELOPER_API_PROVIDER | typeof CLOUDFLARE_GATEWAY_PROVIDER;
	isCloudflareGateway: boolean;
}

function resolveGeminiDeveloperEndpoint(): GeminiDeveloperEndpoint {
	const configuredHost = Bun.env.GOOGLE_GEMINI_BASE_URL?.trim().replace(/\/+$/, "");
	const host = configuredHost || DEFAULT_DEVELOPER_API_HOST;
	let parsed: URL;
	try {
		parsed = new URL(host);
	} catch {
		throw new SearchProviderError("gemini", "GOOGLE_GEMINI_BASE_URL must be a valid absolute URL", 400);
	}
	if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
		throw new SearchProviderError("gemini", "GOOGLE_GEMINI_BASE_URL must use HTTP or HTTPS", 400);
	}
	const isCloudflareGateway = parsed.hostname === "gateway.ai.cloudflare.com";
	return {
		url: `${host}/${DEVELOPER_API_VERSION}`,
		authProvider: isCloudflareGateway ? CLOUDFLARE_GATEWAY_PROVIDER : DEVELOPER_API_PROVIDER,
		isCloudflareGateway,
	};
}

const GEMINI_PROVIDERS = ["google-gemini-cli", "google-antigravity"] as const;
type GeminiProviderId = (typeof GEMINI_PROVIDERS)[number];

interface GeminiToolParams {
	google_search?: Record<string, unknown>;
	code_execution?: Record<string, unknown>;

View on GitHub (pinned to 9690622007)

Solutions

  1. Set GOOGLE_GEMINI_BASE_URL to a full absolute URL including the scheme, e.g. https://generativelanguage.googleapis.com
  2. If you use the default endpoint, unset the variable entirely so the built-in default host applies
  3. Echo the variable (`printenv GOOGLE_GEMINI_BASE_URL | cat -A`) to spot hidden quotes/whitespace

Example fix

// before
GOOGLE_GEMINI_BASE_URL=generativelanguage.googleapis.com
// after
GOOGLE_GEMINI_BASE_URL=https://generativelanguage.googleapis.com
Defensive patterns

Strategy: validation

Validate before calling

const v = Bun.env.GOOGLE_GEMINI_BASE_URL?.trim();
if (v) {
  try {
    new URL(v); // throws if not absolute
  } catch {
    throw new Error("GOOGLE_GEMINI_BASE_URL must be absolute, e.g. https://generativelanguage.googleapis.com");
  }
}

Type guard

function isAbsoluteUrl(value: string | undefined): boolean {
  if (!value) return true; // unset uses default
  try { new URL(value.trim()); return true; } catch { return false; }
}

Try / catch

try {
  results = await searchGemini(query);
} catch (err) {
  if (err instanceof SearchProviderError && err.message.includes("must be a valid absolute URL")) {
    logger.error("Fix GOOGLE_GEMINI_BASE_URL: include the https:// scheme", { cause: err.message });
    results = await fallbackSearch(query);
  } else throw err;
}

Prevention

When it happens

Trigger: GOOGLE_GEMINI_BASE_URL set to a scheme-less value like 'generativelanguage.googleapis.com', a value with stray quotes/whitespace that fails URL parsing, or any placeholder/nonsense string. Triggered by endpoint() or isAvailable() when using the Gemini developer search provider.

Common situations: Users copying the host without the https:// prefix from docs, .env quoting mistakes, or CI injecting unset-marker placeholders into the variable.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/d0d995e47fcb5b22. Report an issue: GitHub.