{"record":{"id":"1409f1d499527be1","repo":"can1357/oh-my-pi","slug":"google-gemini-base-url-must-use-http-or-https","errorCode":null,"errorMessage":"GOOGLE_GEMINI_BASE_URL must use HTTP or HTTPS","messagePattern":"GOOGLE_GEMINI_BASE_URL must use HTTP or HTTPS","errorType":"validation","errorClass":"SearchProviderError","httpStatus":400,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/gemini.ts","lineNumber":59,"sourceCode":"}\n\ninterface GeminiDeveloperEndpoint {\n\turl: string;\n\tauthProvider: typeof DEVELOPER_API_PROVIDER | typeof CLOUDFLARE_GATEWAY_PROVIDER;\n\tisCloudflareGateway: boolean;\n}\n\nfunction resolveGeminiDeveloperEndpoint(): GeminiDeveloperEndpoint {\n\tconst configuredHost = Bun.env.GOOGLE_GEMINI_BASE_URL?.trim().replace(/\\/+$/, \"\");\n\tconst host = configuredHost || DEFAULT_DEVELOPER_API_HOST;\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(host);\n\t} catch {\n\t\tthrow new SearchProviderError(\"gemini\", \"GOOGLE_GEMINI_BASE_URL must be a valid absolute URL\", 400);\n\t}\n\tif (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n\t\tthrow new SearchProviderError(\"gemini\", \"GOOGLE_GEMINI_BASE_URL must use HTTP or HTTPS\", 400);\n\t}\n\tconst isCloudflareGateway = parsed.hostname === \"gateway.ai.cloudflare.com\";\n\treturn {\n\t\turl: `${host}/${DEVELOPER_API_VERSION}`,\n\t\tauthProvider: isCloudflareGateway ? CLOUDFLARE_GATEWAY_PROVIDER : DEVELOPER_API_PROVIDER,\n\t\tisCloudflareGateway,\n\t};\n}\n\nconst GEMINI_PROVIDERS = [\"google-gemini-cli\", \"google-antigravity\"] as const;\ntype GeminiProviderId = (typeof GEMINI_PROVIDERS)[number];\n\ninterface GeminiToolParams {\n\tgoogle_search?: Record<string, unknown>;\n\tcode_execution?: Record<string, unknown>;\n\turl_context?: Record<string, unknown>;\n}\n","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/gemini.ts#L41-L77","documentation":"resolveGeminiDeveloperEndpoint() throws this when GOOGLE_GEMINI_BASE_URL parses as a URL but its protocol is neither https: nor http:. The Gemini developer endpoint must be fetched over HTTP(S); other schemes (ftp:, ws:, file:, etc.) are rejected with a 400 SearchProviderError before any request is sent.","triggerScenarios":"GOOGLE_GEMINI_BASE_URL set with a non-HTTP scheme — e.g. 'wss://gateway.example.com', 'file:///etc/gemini', or a typo like 'https:/host' that the URL parser resolves to a different scheme. Reached via endpoint() or isAvailable().","commonSituations":"Pointing the base URL at a websocket or unix-file endpoint, scheme typos, or URL values mangled by shell escaping that shift the colon placement.","solutions":["Change the value to start with https:// (or http:// only for local testing/proxies that require it)","Print the parsed protocol (`new URL(value).protocol`) to see what the parser derives from your value","Unset GOOGLE_GEMINI_BASE_URL to use the default HTTPS developer API host"],"exampleFix":"// before\nGOOGLE_GEMINI_BASE_URL=wss://gemini-proxy.internal\n// after\nGOOGLE_GEMINI_BASE_URL=https://gemini-proxy.internal","handlingStrategy":"validation","validationCode":"const v = Bun.env.GOOGLE_GEMINI_BASE_URL?.trim();\nif (v) {\n  const proto = new URL(v).protocol;\n  if (proto !== \"https:\" && proto !== \"http:\") {\n    throw new Error(`GOOGLE_GEMINI_BASE_URL must use http/https, got '${proto}'`);\n  }\n}","typeGuard":"function isHttpLikeBase(value: string | undefined): boolean {\n  if (!value) return true;\n  try {\n    const p = new URL(value.trim()).protocol;\n    return p === \"http:\" || p === \"https:\";\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  results = await searchGemini(query);\n} catch (err) {\n  if (err instanceof SearchProviderError && err.message.includes(\"must use HTTP or HTTPS\")) {\n    logger.error(\"GOOGLE_GEMINI_BASE_URL scheme rejected — use https://\", { cause: err.message });\n    results = await fallbackSearch(query);\n  } else throw err;\n}","preventionTips":["Configure only http(s) endpoints; websocket or file schemes will be rejected even if technically reachable","Double-check scheme spelling (https:// not https:/ or htps://) — parser failures surface as scheme errors","Run a startup config check that parses and asserts the protocol","Prefer unsetting the var to inherit the default HTTPS host"],"tags":["configuration","scheme","url-validation"],"backgroundTag":"invalid-base-url","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}