jlcodes99/cockpit-tools · error
PROVIDER_BASE_URL_EXISTS
PROVIDER_BASE_URL_EXISTS
Error message
PROVIDER_BASE_URL_EXISTS
What it means
createCodexModelProvider rejects a new provider whose baseUrl normalizes to the same value as an existing provider. The service enforces uniqueness of provider base URLs by comparing normalizeCodexModelProviderBaseUrl(item.baseUrl) across all stored providers. It is a deliberate duplicate-prevention guard, not a network or runtime failure.
Source
Thrown at src/services/codexModelProviderService.ts:589
boundInstanceId?: string;
website?: string;
apiKeyUrl?: string;
wireApi?: CodexProviderWireApi;
supportsWebsockets?: boolean;
enableModePreference?: CodexProviderEnableModePreference;
integrationType?: 'sub2api' | 'new_api';
boundOauthAccountId?: string | null;
initialApiKey?: string;
initialApiKeyName?: string;
}): Promise<CodexModelProvider> {
const name = sanitizeName(input.name);
const baseUrl = normalizeBaseUrlForStore(input.baseUrl);
const normalizedBaseUrl = normalizeCodexModelProviderBaseUrl(baseUrl);
if (!name) throw new Error('PROVIDER_NAME_REQUIRED');
if (!normalizedBaseUrl) throw new Error('PROVIDER_BASE_URL_INVALID');
const providers = await ensureProvidersLoaded();
if (providers.some((item) => normalizeCodexModelProviderBaseUrl(item.baseUrl) === normalizedBaseUrl)) {
throw new Error('PROVIDER_BASE_URL_EXISTS');
}
const now = Date.now();
const wireApi = normalizeWireApi(input.wireApi);
const provider: CodexModelProvider = {
id: createProviderId(),
name,
baseUrl,
sourceTag: sanitizeName(input.sourceTag ?? '') || undefined,
integrationType: normalizeIntegrationType(input.integrationType),
modelCatalog:
normalizeModelCatalog(input.modelCatalog) ??
presetModelCatalogForBaseUrl(baseUrl),
modelContextWindows: normalizeModelContextWindows(
input.modelContextWindows,
normalizeModelCatalog(input.modelCatalog) ??
presetModelCatalogForBaseUrl(baseUrl) ??
[],
),View on GitHub (pinned to 1ed8b77992)
Solutions
- Search existing providers for one whose baseUrl matches (after normalization) and reuse/update it via updateCodexModelProvider instead of creating a new one.
- Change the new provider's baseUrl to a distinct endpoint (different host, port, or path prefix).
- If the old duplicate is stale, delete it first, then re-run createCodexModelProvider.
- Wrap the call in try/catch for 'PROVIDER_BASE_URL_EXISTS' and fall back to an update path when the message matches.
Example fix
// before: blind create, throws on second run
await createCodexModelProvider({ name: 'proxy', baseUrl: 'http://localhost:8080/v1' });
// after: reuse or update the existing provider
const existing = (await listCodexModelProviders()).find(
(p) => normalizeCodexModelProviderBaseUrl(p.baseUrl) === normalizeCodexModelProviderBaseUrl('http://localhost:8080/v1'),
);
const provider = existing
? await updateCodexModelProvider(existing.id, { name: 'proxy' })
: await createCodexModelProvider({ name: 'proxy', baseUrl: 'http://localhost:8080/v1' }); Defensive patterns
Strategy: validation
Validate before calling
import { listCodexModelProviders } from './codexModelProviderService';
// approximate normalizer: compare trimmed, lower-cased URL without trailing slash
const norm = (u: string) => new URL(u).toString().replace(/\/$/, '').toLowerCase();
const normalized = norm(baseUrl);
const exists = (await listCodexModelProviders()).some((p) => norm(p.baseUrl) === normalized);
if (exists) throw new Error('PROVIDER_BASE_URL_EXISTS'); Try / catch
try {
await createCodexModelProvider({ name, baseUrl });
} catch (e) {
if ((e as Error).message === 'PROVIDER_BASE_URL_EXISTS') {
// fall back to locating and updating the existing provider
} else throw e;
} Prevention
- Always list providers and compare normalized base URLs before creating a new one.
- Make provider creation idempotent in scripts: check-then-create or upsert.
- Debounce/disable the save button in UIs to prevent double submits.
- Clean up stale provider rows during environment resets.
When it happens
Trigger: Calling createCodexModelProvider({ name, baseUrl, ... }) when any already-stored provider's baseUrl, after normalization (scheme/host/path canonicalization), equals the normalized form of the incoming baseUrl. Thrown at src/services/codexModelProviderService.ts:589 before any provider record is created.
Common situations: Re-running an init/import script that already created the provider; adding a second provider entry pointing at the same gateway (e.g. http://localhost:8080 vs localhost:8080/v1, which normalize to the same value); switching a proxy to a new port but leaving the old provider row in place; UI double-submit of the save form (handleSaveProvider).
Related errors
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/c4342ed8509ebdc0.
Report an issue: GitHub.