{"record":{"id":"828ce6099ffd6968","repo":"jlcodes99/cockpit-tools","slug":"provider-base-url-invalid","errorCode":"PROVIDER_BASE_URL_INVALID","errorMessage":"PROVIDER_BASE_URL_INVALID","messagePattern":"PROVIDER_BASE_URL_INVALID","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/codexModelProviderService.ts","lineNumber":586,"sourceCode":"  supportsVision?: boolean;\n  modelCapabilities?: Record<string, { supportsVision?: boolean }>;\n  visionRoutingModel?: string;\n  boundInstanceId?: string;\n  website?: string;\n  apiKeyUrl?: string;\n  wireApi?: CodexProviderWireApi;\n  supportsWebsockets?: boolean;\n  enableModePreference?: CodexProviderEnableModePreference;\n  integrationType?: 'sub2api' | 'new_api';\n  boundOauthAccountId?: string | null;\n  initialApiKey?: string;\n  initialApiKeyName?: string;\n}): Promise<CodexModelProvider> {\n  const name = sanitizeName(input.name);\n  const baseUrl = normalizeBaseUrlForStore(input.baseUrl);\n  const normalizedBaseUrl = normalizeCodexModelProviderBaseUrl(baseUrl);\n  if (!name) throw new Error('PROVIDER_NAME_REQUIRED');\n  if (!normalizedBaseUrl) throw new Error('PROVIDER_BASE_URL_INVALID');\n  const providers = await ensureProvidersLoaded();\n  if (providers.some((item) => normalizeCodexModelProviderBaseUrl(item.baseUrl) === normalizedBaseUrl)) {\n    throw new Error('PROVIDER_BASE_URL_EXISTS');\n  }\n  const now = Date.now();\n  const wireApi = normalizeWireApi(input.wireApi);\n  const provider: CodexModelProvider = {\n    id: createProviderId(),\n    name,\n    baseUrl,\n    sourceTag: sanitizeName(input.sourceTag ?? '') || undefined,\n    integrationType: normalizeIntegrationType(input.integrationType),\n    modelCatalog:\n      normalizeModelCatalog(input.modelCatalog) ??\n      presetModelCatalogForBaseUrl(baseUrl),\n    modelContextWindows: normalizeModelContextWindows(\n      input.modelContextWindows,\n      normalizeModelCatalog(input.modelCatalog) ??","sourceCodeStart":568,"sourceCodeEnd":604,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/services/codexModelProviderService.ts#L568-L604","documentation":"createCodexModelProvider throws PROVIDER_BASE_URL_INVALID when normalizeCodexModelProviderBaseUrl yields an empty/invalid result for the supplied baseUrl. A valid, normalized base URL is required so providers can be de-duplicated and reached at request time.","triggerScenarios":"input.baseUrl is empty, whitespace, or fails normalizeBaseUrlForStore / normalizeCodexModelProviderBaseUrl normalization (missing scheme, malformed URL).","commonSituations":"Leaving the base-URL field blank in the provider form, typing 'localhost:8080' without a scheme, pasting a URL with trailing junk or an unsupported protocol.","solutions":["Enter a complete base URL including scheme, e.g. https://api.openai.com/v1 or http://localhost:8080/v1","Prepend https:// to scheme-less URLs before saving","Verify normalizeCodexModelProviderBaseUrl's rules (allowed schemes, path handling) and match them","Catch PROVIDER_BASE_URL_INVALID and mark the base-URL field invalid in the UI"],"exampleFix":"// before\nbaseUrl: 'localhost:8080/v1'\n// after\nbaseUrl: 'http://localhost:8080/v1'","handlingStrategy":"validation","validationCode":"function isValidBaseUrl(u: string): boolean {\n  try { const url = new URL(u.trim()); return url.protocol === 'http:' || url.protocol === 'https:'; }\n  catch { return false; }\n}\nif (!isValidBaseUrl(input.baseUrl)) throw new Error('PROVIDER_BASE_URL_INVALID');","typeGuard":"function hasValidBaseUrl(input: { baseUrl?: string }): input is { baseUrl: string } {\n  if (typeof input.baseUrl !== 'string') return false;\n  try { const u = new URL(input.baseUrl.trim()); return u.protocol === 'http:' || u.protocol === 'https:'; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  await createCodexModelProvider(input);\n} catch (e) {\n  if (e instanceof Error && e.message === 'PROVIDER_BASE_URL_INVALID') {\n    setBaseUrlFieldError('Enter a valid base URL including http(s)://');\n  } else throw e;\n}","preventionTips":["Always include the scheme (https:// or http://) in base URLs","Validate the URL with new URL() in the form before submitting","Trim and normalize the input on blur so users see the value that will be saved","Document accepted URL formats (host, optional /v1 path) in the provider form UI"],"tags":["validation","url","codex","input-validation"],"backgroundTag":"invalid-url","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}