farion1231/cc-switch · warning · PiFormValidationError
pi.form.effectiveApiRequired
Error message
pi.form.effectiveApiRequired
What it means
Thrown per-model in PiProviderForm's submit() when creating (!isEdit) with neither a per-model passthrough 'api' override (model.passthrough.api) nor a provider-level api selected (PiProviderForm.tsx:1174-1180). Pi needs a wire format (API family) to talk to the endpoint. Edit mode is exempt by design: existing explicit nodes may be partial overrides of a Pi built-in provider and inherit its transport (comment at lines 1170-1173). The message interpolates the model id; fieldSelector '#pi-provider-api-select' with revealAdvanced=true focuses the API selector.
Source
Thrown at src/components/providers/forms/PiProviderForm.tsx:1181
true,
);
}
// Pi's schema supports rare per-model api/baseUrl overrides. Keep
// imported values losslessly, but use the provider-level format and
// endpoint as the normal product model.
const modelApi =
typeof model.passthrough.api === "string"
? 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 } : {}),
...(includeInputView on GitHub (pinned to a2e22f3302)
Solutions
- Pick the API format (e.g. the OpenAI- or Anthropic-compatible family) in the provider's advanced/API settings, then save
- Alternatively set a per-model passthrough "api" string in the model's advanced JSON
- When building custom flows, default api from the selected preset's template values
Example fix
// before
const values = { /* ... */ api: "" };
// after
const values = { /* ... */ api: "openai" }; // or "anthantic"-family per your endpoint; must match a known Pi api format Defensive patterns
Strategy: validation
Validate before calling
const modelApi = typeof model.passthrough.api === "string" ? model.passthrough.api.trim() : "";
if (!isEdit && !modelApi && api.trim() === "") {
setFormError(t("pi.form.effectiveApiRequired", { id: model.id }));
return;
} Try / catch
try {
await submit(identity);
} catch (error) {
if (error instanceof Error && error.name === "PiFormValidationError") { /* focuses '#pi-provider-api-select' after revealing advanced settings */ return; }
throw error;
} Prevention
- Default the api format from the selected preset's templateValues
- Disable Save in create mode until api is chosen or a per-model passthrough api exists
- Remember edit mode is exempt: partial overrides inherit the built-in provider's transport
When it happens
Trigger: Creating a provider, leaving the API protocol dropdown empty, and not setting 'api' in any model's advanced passthrough JSON; selecting 'Custom' preset which does not prefill an api format.
Common situations: User assumes baseUrl alone is enough; preset template lacked an api value; per-model overrides were cleared during import; user confusion between the provider-level selector and the per-model passthrough field.
Related errors
- pi.form.effectiveBaseUrlRequired
- pi.form.selectPresetRequired
- jsonEditor.mustBeObject
- pi.form.nameRequired
- pi.form.providerKeyRequired
AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16).
Data as JSON: /api/errors/91973c8ec864c45d.
Report an issue: GitHub.