farion1231/cc-switch · error · PiFormValidationError
Model {{id}} needs a base URL, either directly or from the p
Error message
Model {{id}} needs a base URL, either directly or from the provider What it means
Companion to the API check: PiProviderForm computes effectiveUrl = model's passthrough baseUrl override (trimmed) || provider-level baseUrl (trimmed) and, in create mode, throws pi.form.effectiveBaseUrlRequired (with the model id, focusing #pi-provider-base-url) when it is empty. Without a base URL, custom (non-built-in) providers have no endpoint to send requests to. Edit mode is exempt for the same partial-override reason as the API check.
Source
Thrown at src/components/providers/forms/PiProviderForm.tsx:1189
? model.passthrough.api.trim()
: "";
const modelBaseUrl =
typeof model.passthrough.baseUrl === "string"
? model.passthrough.baseUrl.trim()
: "";
// Existing explicit nodes may be partial overrides of a Pi built-in
// provider. Pi inherits the built-in transport in that case, so only
// require a complete transport when CC Switch creates a new provider.
if (!isEdit && !modelApi && !api.trim()) {
throw new PiFormValidationError(
t("pi.form.effectiveApiRequired", { id }),
"#pi-provider-api-select",
true,
);
}
const effectiveUrl = modelBaseUrl || baseUrl.trim();
if (!isEdit && !effectiveUrl) {
throw new PiFormValidationError(
t("pi.form.effectiveBaseUrlRequired", { id }),
"#pi-provider-base-url",
);
}
return {
...model.passthrough,
id,
...(includeName ? { name: displayName } : {}),
...(includeReasoning ? { reasoning: model.reasoning } : {}),
...(includeInput
? {
input: withImageInput(
model.input,
supportsImageInput(model.input),
),
}
: {}),
...(contextWindow !== undefined ? { contextWindow } : {}),View on GitHub (pinned to 0b5da51016)
Solutions
- Enter the provider endpoint in the Base URL field, e.g. 'https://api.example.com/v1' (leading/trailing spaces are trimmed away).
- If only one model needs a different endpoint, set its per-model baseUrl passthrough instead of the provider-level field.
- Confirm no whitespace-only value is lingering in the field after paste.
Example fix
// before
const baseUrl = " "; // looks filled, trims to empty
const model = { id: "m1", passthrough: {} };
submit(identity); // throws "Model m1 needs a base URL, ..."
// after
const baseUrl = "https://api.example.com/v1";
submit(identity); Defensive patterns
Strategy: validation
Validate before calling
const effectiveUrl = (typeof model.passthrough.baseUrl === "string" ? model.passthrough.baseUrl.trim() : "") || baseUrl.trim();
if (!isEdit && !effectiveUrl) highlight("#pi-provider-base-url", "Base URL is required"); Type guard
const hasBaseUrl = (m: ModelRow): boolean => (typeof m.passthrough.baseUrl === "string" && m.passthrough.baseUrl.trim().length > 0) || baseUrl.trim().length > 0;
Try / catch
catch (e) {
if (e instanceof PiFormValidationError && e.fieldSelector === "#pi-provider-base-url") { setFormError(e.message); document.querySelector(e.fieldSelector)?.focus(); return; }
throw e;
} Prevention
- Trim the base URL field on blur so whitespace-only values show as empty.
- Require the URL field whenever the custom (non-preset) path is active.
When it happens
Trigger: Creating a custom provider without filling the Base URL field while none of the models carry a baseUrl passthrough; whitespace-only base URL (it is trimmed, so ' ' counts as empty); preset switched to custom wiped the URL.
Common situations: User expects preset defaults to apply in the custom path; proxy/gateway deployments where the URL was meant to be added later; trailing-space paste making the field look filled.
Related errors
- Model {{id}} needs an API, either directly or from the provi
- {{label}} must be an absolute HTTP or HTTPS URL
- {{label}} must be a number greater than 0
- Select a preset or custom configuration first
- Configuration must be a JSON object, not an array or other t
AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20).
Data as JSON: /api/errors/90a7d3f0adb6ecc4.
Report an issue: GitHub.