farion1231/cc-switch · warning · PiFormValidationError
pi.form.selectPresetRequired
Error message
pi.form.selectPresetRequired
What it means
Thrown by the Pi provider form's submit() in CC Switch (PiProviderForm.tsx:1067-1069) when saving a NEW Pi provider while selectedPresetId is still null. New Pi providers derive their transport defaults and template values from a built-in preset (or the explicit 'custom' entry), so creation without a selection is rejected. It is a PiFormValidationError with no fieldSelector: the catch block (lines 1254-1285) renders it as an inline form error plus a toast, and nothing is saved.
Source
Thrown at src/components/providers/forms/PiProviderForm.tsx:1068
});
if (!applied) return;
includeCompatRef.current = includeCompat;
setProviderCompat(value);
},
[updateSettingsConfig],
);
const handleProviderKeyChange = useCallback((value: string) => {
const normalized = value.toLowerCase().replace(/[^a-z0-9-]/g, "");
setProviderKey(normalized);
}, []);
const submit = async (identity: ProviderFormData) => {
onSubmittingChange?.(true);
setFormError(null);
try {
if (!isEdit && selectedPresetId === null) {
throw new PiFormValidationError(t("pi.form.selectPresetRequired"));
}
if (!parseJsonObject(identity.settingsConfig)) {
throw new PiFormValidationError(
t("jsonEditor.mustBeObject"),
"#pi-settings-config",
);
}
const trimmedName = identity.name.trim();
const trimmedKey = providerKey.trim();
if (!trimmedName) {
throw new PiFormValidationError(
t("pi.form.nameRequired"),
'input[name="name"]',
);
}
if (!isEdit && !trimmedKey) {
throw new PiFormValidationError(
t("pi.form.providerKeyRequired"),View on GitHub (pinned to a2e22f3302)
Solutions
- Select a preset (or 'Custom') in the preset picker, then save again
- Initialize selectedPresetId to a sensible default (first preset or 'custom') when the dialog opens in create mode
- Disable the Save button while !isEdit && selectedPresetId === null, mirroring the form's own hasConfigurationSelection check (PiProviderForm.tsx:540)
- In tests, drive the preset selector (or inject state) so selectedPresetId is non-null before submitting
Example fix
// before (dialog opens with no default) const [selectedPresetId, setSelectedPresetId] = useState<string | null>(null); // after (create mode defaults to Custom, matching the guard's semantics) const [selectedPresetId, setSelectedPresetId] = useState<string | null>( isEdit ? null : "custom", );
Defensive patterns
Strategy: validation
Validate before calling
// Before invoking submit for a new Pi provider:
if (!isEdit && selectedPresetId === null) {
setFormError(t("pi.form.selectPresetRequired"));
return; // don't call submit
} Try / catch
try {
await submit(identity);
} catch (error) {
if (error instanceof Error && error.name === "PiFormValidationError") {
// expected inline validation error; already surfaced by the form
return;
}
throw error;
} Prevention
- Default selectedPresetId ('custom' or first preset) when the create dialog opens
- Disable Save while !isEdit && selectedPresetId === null, reusing the form's hasConfigurationSelection logic
- In tests, always drive the preset selector before submitting
When it happens
Trigger: Calling submit() with isEdit=false and selectedPresetId===null: the user opened the 'Add provider' dialog and clicked Save without ever touching ProviderPresetSelector, or the useState holding the selection was reset by a remount/HMR before submit.
Common situations: Hitting Save immediately after opening the create dialog; embedding PiProviderForm in a custom wrapper that skips the preset selector; React StrictMode double-mount losing uncommitted picker state; automated tests submitting the form programmatically without selecting a preset.
Related errors
- pi.form.absoluteHttpUrlRequired
- jsonEditor.mustBeObject
- pi.form.nameRequired
- pi.form.providerKeyRequired
- pi.form.credentialRequired
AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16).
Data as JSON: /api/errors/821dc89609cefea9.
Report an issue: GitHub.