farion1231/cc-switch · error · PiFormValidationError

Model {{id}} needs an API, either directly or from the provi

Error message

Model {{id}} needs an API, either directly or from the provider

What it means

PiProviderForm computes each model's transport: modelApi = trimmed passthrough api override (model.passthrough.api), falling back to the provider-level api field. In create mode it throws pi.form.effectiveApiRequired (with the model id, focusing #pi-provider-api-select, revealing advanced) when both are empty — the model would have no API type to route with. Edit mode is exempt because existing explicit nodes may be partial overrides of a Pi built-in provider that inherits the built-in transport.

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 } : {}),
          ...(includeInput

View on GitHub (pinned to 0b5da51016)

Solutions

  1. Pick a value in the provider-level API selector (advanced section auto-reveals) such as 'anthropic' or 'openai', then resubmit.
  2. Alternatively give the specific model an api override in its passthrough settings if it must diverge from the provider default.
  3. If you were editing an existing provider and hit this, verify you did not accidentally open the create form with cleared transport state.

Example fix

// before
const api = ""; // provider API select left empty
const model = { id: "m1", passthrough: {} }; // no api override
submit(identity); // throws "Model m1 needs an API, ..."

// after
const api = "openai"; // set provider-level API type
submit(identity);
Defensive patterns

Strategy: validation

Validate before calling

const modelApi = typeof model.passthrough.api === "string" ? model.passthrough.api.trim() : "";
if (!isEdit && !modelApi && !api.trim()) highlight("#pi-provider-api-select", "Choose the API type");

Type guard

const hasApiOverride = (m: ModelRow): boolean => typeof m.passthrough.api === "string" && m.passthrough.api.trim().length > 0;

Try / catch

catch (e) {
  if (e instanceof PiFormValidationError && e.fieldSelector === "#pi-provider-api-select") { setAdvancedOpen(true); setFormError(e.message); return; }
  throw e;
}

Prevention

When it happens

Trigger: Creating a custom provider, choosing/entering models, but leaving the provider-level API select empty while no model carries a passthrough api; also when the api select was cleared after a preset switch to 'custom'.

Common situations: Custom (non-preset) configuration where the user assumes the API type is inferred from the base URL; importing models whose passthrough lacks 'api'; preset data lost during form state resets.

Related errors


AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20). Data as JSON: /api/errors/a0a1eda4e445e103. Report an issue: GitHub.