farion1231/cc-switch · warning · PiFormValidationError

Select a preset or custom configuration first

Error message

Select a preset or custom configuration first

What it means

PiProviderForm throws this PiFormValidationError when submit() runs in create mode (isEdit === false) and selectedPresetId is still null. The Pi provider form is preset-driven: a new provider must either clone a bundled preset or explicitly pick the 'custom' configuration before any other validation runs. It is the first gate in the submit() chain, so nothing else is validated until it passes.

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 0b5da51016)

Solutions

  1. In the create flow, choose a preset (or the 'custom configuration' option) so selectedPresetId becomes non-null, then resubmit.
  2. If you are driving the form programmatically, set the preset selection state before invoking submit().
  3. If users should be able to submit without a preset, pass an explicit 'custom' preset id instead of leaving selectedPresetId null.

Example fix

// before
const [selectedPresetId, setSelectedPresetId] = useState<string | null>(null);
// user clicks submit -> throws 'Select a preset or custom configuration first'

// after
const [selectedPresetId, setSelectedPresetId] = useState<string | null>(CUSTOM_PRESET_ID);
// or disable submit until a choice is made:
<button disabled={!isEdit && selectedPresetId === null}>Save</button>
Defensive patterns

Strategy: validation

Validate before calling

const canSubmit = isEdit || selectedPresetId !== null;
// render: <button disabled={!canSubmit}>Save</button>

Try / catch

try {
  await submit(identity);
} catch (e) {
  if (e instanceof PiFormValidationError) {
    // e.fieldSelector is undefined here; prompt user to pick a preset
    setFormError(e.message);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Clicking the form's submit/confirm button in the 'Add provider' (create) flow without ever interacting with the preset selector, so selectedPresetId stays null. Only fires on create; editing an existing provider (isEdit) skips the check entirely.

Common situations: A UI regression or custom launcher invokes submit() before the preset step is completed; automation/tests call submit() directly on a fresh form; the preset picker was skipped because the dialog was opened in an unexpected state.

Related errors


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