farion1231/cc-switch · warning · PiFormValidationError

Model {{index}} needs an ID

Error message

Model {{index}} needs an ID

What it means

While normalizing the model list, PiProviderForm checks each row's id and throws pi.form.modelIdRequired (with 1-based index, focusing #pi-model-id-<rowKey> and revealing advanced fields) when model.id.length === 0. Unlike the name field, ids are deliberately NOT trimmed — the source comment notes Pi treats model ids as opaque strings — so an id of only whitespace still counts as non-empty, but an untouched empty row fails.

Source

Thrown at src/components/providers/forms/PiProviderForm.tsx:1111

          "#pi-api-key",
        );
      }
      if (!isEdit && models.length === 0) {
        throw new PiFormValidationError(
          t("pi.form.modelRequired"),
          "#pi-add-model",
          true,
        );
      }

      const headers = normalizeRequestHeaders(providerHeaders);
      const seen = new Set<string>();
      const normalizedModels = models.map((model, index) => {
        // Pi treats model IDs as opaque strings. Trimming would rename an
        // imported model.
        const id = model.id;
        if (id.length === 0) {
          throw new PiFormValidationError(
            t("pi.form.modelIdRequired", { index: index + 1 }),
            `#pi-model-id-${model.key}`,
            true,
          );
        }
        if (seen.has(id)) {
          throw new PiFormValidationError(
            t("pi.form.duplicateModel", { id }),
            `#pi-model-id-${model.key}`,
            true,
          );
        }
        seen.add(id);
        const displayName = model.name.trim();
        const includeName = !isEdit || model.hasName;
        const includeReasoning = !isEdit || model.hasReasoning;
        const includeInput = !isEdit || model.hasInput;
        const includeContextWindow = !isEdit || model.hasContextWindow;

View on GitHub (pinned to 0b5da51016)

Solutions

  1. Fill the Model ID input of the row indicated by the {index} in the message (e.g. 'Model 2' = second row) with the exact id Pi/APIs expect, such as 'claude-sonnet-4'.
  2. Remove empty placeholder rows you did not intend to configure before submitting.
  3. When importing, skip or populate rows whose id is missing.

Example fix

// before
const models = [
  { key: "m1", id: "", name: "My model" }, // id never filled
];
submit(identity); // throws 'Model 1 needs an ID'

// after
const models = [
  { key: "m1", id: "gpt-5.2", name: "My model" },
];
submit(identity);
Defensive patterns

Strategy: validation

Validate before calling

const emptyIdIndex = models.findIndex((m) => m.id.length === 0);
if (emptyIdIndex >= 0) focusRow(`#pi-model-id-${models[emptyIdIndex].key}`);

Try / catch

catch (e) {
  if (e instanceof PiFormValidationError) { setAdvancedOpen(e.revealAdvanced || advancedOpen); document.querySelector(e.fieldSelector ?? "")?.scrollIntoView({ block: "center" }); return; }
  throw e;
}

Prevention

When it happens

Trigger: Clicking 'Add model' and saving without typing an id; deleting the id text of an auto-created empty row; importing models where one row's id is "".

Common situations: Users add a model row to see what it does, fill only the display name, and submit; a duplicate-check flow removed an id; keyboard focus loss leaves the id input blank.

Related errors


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