{"record":{"id":"79b5a6651bd9aaca","repo":"farion1231/cc-switch","slug":"add-at-least-one-model","errorCode":null,"errorMessage":"Add at least one model","messagePattern":"Add at least one model","errorType":"validation","errorClass":"PiFormValidationError","httpStatus":null,"severity":"warning","filePath":"src/components/providers/forms/PiProviderForm.tsx","lineNumber":1097,"sourceCode":"        throw new PiFormValidationError(\n          t(\"pi.form.nameRequired\"),\n          'input[name=\"name\"]',\n        );\n      }\n      if (!isEdit && !trimmedKey) {\n        throw new PiFormValidationError(\n          t(\"pi.form.providerKeyRequired\"),\n          \"#pi-provider-key\",\n        );\n      }\n      if (!isEdit && selectedPreset && apiKey.length === 0) {\n        throw new PiFormValidationError(\n          t(\"pi.form.credentialRequired\"),\n          \"#pi-api-key\",\n        );\n      }\n      if (!isEdit && models.length === 0) {\n        throw new PiFormValidationError(\n          t(\"pi.form.modelRequired\"),\n          \"#pi-add-model\",\n          true,\n        );\n      }\n\n      const headers = normalizeRequestHeaders(providerHeaders);\n      const seen = new Set<string>();\n      const normalizedModels = models.map((model, index) => {\n        // Pi treats model IDs as opaque strings. Trimming would rename an\n        // imported model.\n        const id = model.id;\n        if (id.length === 0) {\n          throw new PiFormValidationError(\n            t(\"pi.form.modelIdRequired\", { index: index + 1 }),\n            `#pi-model-id-${model.key}`,\n            true,\n          );","sourceCodeStart":1079,"sourceCodeEnd":1115,"githubUrl":"https://github.com/farion1231/cc-switch/blob/0b5da510168914b251481654a568c3ffacd62cf4/src/components/providers/forms/PiProviderForm.tsx#L1079-L1115","documentation":"PiProviderForm refuses to create a provider with an empty model list: submit() throws pi.form.modelRequired when !isEdit && models.length === 0, focusing #pi-add-model and setting revealAdvanced so the models section (an advanced field) is expanded. Pi routes requests per model id, so a provider without at least one model is unusable.","triggerScenarios":"Submitting the create form without having pressed 'Add model' even once; deleting the last model row (which leaves models as []) and saving.","commonSituations":"Users fill identity/transport fields and assume models are optional; the models section is collapsed under 'Advanced' and gets overlooked; a removed default model row empties the list.","solutions":["Open the models section (it auto-expands via revealAdvanced) and add at least one model with its id.","If you imported a preset that normally seeds models, re-select the preset so model rows are populated, then submit.","For programmatic submissions, ensure the models array passed to the form state contains >= 1 entry."],"exampleFix":"// before\nconst models: ModelRow[] = []; // no rows added\nsubmit(identity); // throws 'Add at least one model'\n\n// after\nconst models = [{ key: \"m1\", id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", /* ... */ }];\nsubmit(identity);","handlingStrategy":"validation","validationCode":"const modelsOk = isEdit || models.length > 0;\nif (!modelsOk) expandAdvanced(\"#pi-add-model\"); // and show inline hint","typeGuard":null,"tryCatchPattern":"catch (e) {\n  if (e instanceof PiFormValidationError && e.revealAdvanced) { setAdvancedOpen(true); setFormError(e.message); return; }\n  throw e;\n}","preventionTips":["Seed at least one model row when a preset is selected.","Prevent deleting the last model row, or prompt before doing so."],"tags":["pi","form-validation","model-list","react"],"backgroundTag":"required-form-field-missing","analyzedSha":"0b5da510168914b251481654a568c3ffacd62cf4","analyzedAt":"2026-08-20T14:29:00.113Z","contentChangedAt":"2026-08-20T14:29:00.113Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}