farion1231/cc-switch · warning · PiFormValidationError

pi.form.duplicateModel

Error message

pi.form.duplicateModel

What it means

Thrown per-model in PiProviderForm's submit() when two model rows share the exact same id string (PiProviderForm.tsx:1117-1124). Ids feed a Set ('seen') during normalization, and Pi's settings require unique model keys. Comparison is exact and case-sensitive: 'GPT' and 'gpt' are distinct and both pass. The message interpolates the duplicated id; fieldSelector '#pi-model-id-{model.key}' with revealAdvanced=true focuses the offending row.

Source

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

          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;
        const includeMaxTokens = !isEdit || model.hasMaxTokens;
        if (includeName && !displayName) {
          throw new PiFormValidationError(
            t("pi.form.modelNameRequired", { index: index + 1 }),
            `#pi-model-name-${model.key}`,
            true,
          );

View on GitHub (pinned to a2e22f3302)

Solutions

  1. Rename or delete the duplicate row identified by the error message
  2. If two configs of one model are intended, give them distinct ids (for example a '-reasoning' suffix)
  3. Dedupe rows by id (case-sensitively) before enabling Save

Example fix

// before
const ids = models.map((m) => m.id);

// after (block duplicates before submit)
const ids = models.map((m) => m.id);
const hasDupes = new Set(ids).size !== ids.length;
<button type="submit" disabled={hasDupes}>Save</button>;
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set<string>();
for (const [i, m] of models.entries()) {
  if (seen.has(m.id)) {
    setFormError(t("pi.form.duplicateModel", { id: m.id }));
    return;
  }
  seen.add(m.id);
}

Type guard

function hasUniqueModelIds(models: Array<{ id: string }>): boolean {
  return new Set(models.map((m) => m.id)).size === models.length;
}

Try / catch

try {
  await submit(identity);
} catch (error) {
  if (error instanceof Error && error.name === "PiFormValidationError") { /* message names the duplicated id; fieldSelector focuses that row */ return; }
  throw error;
}

Prevention

When it happens

Trigger: Adding the same endpoint model twice; copy-pasting a row to tweak settings without changing its ID; importing a config that already contained a duplicate entry.

Common situations: User wants two configurations of one model (must differentiate ids); merged imports from two sources with overlapping model lists; accidental double-click on an add/import action.

Related errors


AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16). Data as JSON: /api/errors/347c308f37347dfc. Report an issue: GitHub.