{"record":{"id":"ed97730061bdd288","repo":"farion1231/cc-switch","slug":"pi-form-effectivebaseurlrequired","errorCode":null,"errorMessage":"pi.form.effectiveBaseUrlRequired","messagePattern":"pi\\.form\\.effectiveBaseUrlRequired","errorType":"validation","errorClass":"PiFormValidationError","httpStatus":null,"severity":"warning","filePath":"src/components/providers/forms/PiProviderForm.tsx","lineNumber":1189,"sourceCode":"            ? model.passthrough.api.trim()\n            : \"\";\n        const modelBaseUrl =\n          typeof model.passthrough.baseUrl === \"string\"\n            ? model.passthrough.baseUrl.trim()\n            : \"\";\n        // Existing explicit nodes may be partial overrides of a Pi built-in\n        // provider. Pi inherits the built-in transport in that case, so only\n        // require a complete transport when CC Switch creates a new provider.\n        if (!isEdit && !modelApi && !api.trim()) {\n          throw new PiFormValidationError(\n            t(\"pi.form.effectiveApiRequired\", { id }),\n            \"#pi-provider-api-select\",\n            true,\n          );\n        }\n        const effectiveUrl = modelBaseUrl || baseUrl.trim();\n        if (!isEdit && !effectiveUrl) {\n          throw new PiFormValidationError(\n            t(\"pi.form.effectiveBaseUrlRequired\", { id }),\n            \"#pi-provider-base-url\",\n          );\n        }\n        return {\n          ...model.passthrough,\n          id,\n          ...(includeName ? { name: displayName } : {}),\n          ...(includeReasoning ? { reasoning: model.reasoning } : {}),\n          ...(includeInput\n            ? {\n                input: withImageInput(\n                  model.input,\n                  supportsImageInput(model.input),\n                ),\n              }\n            : {}),\n          ...(contextWindow !== undefined ? { contextWindow } : {}),","sourceCodeStart":1171,"sourceCodeEnd":1207,"githubUrl":"https://github.com/farion1231/cc-switch/blob/a2e22f330273a5b6ffa87cb8b82b624601bac562/src/components/providers/forms/PiProviderForm.tsx#L1171-L1207","documentation":"Thrown per-model in PiProviderForm's submit() when creating (!isEdit) with no effective base URL: neither a per-model passthrough 'baseUrl' (model.passthrough.baseUrl, trimmed) nor a provider-level baseUrl is present (PiProviderForm.tsx:1181-1188). The message interpolates the model id; fieldSelector '#pi-provider-base-url' focuses the base URL input. Like the api check, edit mode is exempt because partial overrides of built-in Pi providers inherit the built-in transport.","triggerScenarios":"Creating a custom/self-hosted provider and leaving Base URL blank; entering only whitespace in the base URL field; relying on a per-model baseUrl passthrough that was removed or never imported.","commonSituations":"Preset without a default endpoint URL (custom preset); user expects api selection to imply an endpoint; per-model override typo like 'baseURL' (wrong key) so the passthrough is ignored.","solutions":["Enter the endpoint base URL (e.g. https://api.example.com/v1) in the provider settings and save","Or set \"baseUrl\" (exact key) in the model's advanced passthrough JSON","Disable Save in create mode until api and baseUrl (or per-model overrides) are both resolvable"],"exampleFix":"// before\nbaseUrl: \" \"\n\n// after\nbaseUrl: \"https://api.example.com/v1\"","handlingStrategy":"validation","validationCode":"const modelBaseUrl = typeof model.passthrough.baseUrl === \"string\" ? model.passthrough.baseUrl.trim() : \"\";\nif (!isEdit && !(modelBaseUrl || baseUrl.trim())) {\n  setFormError(t(\"pi.form.effectiveBaseUrlRequired\", { id: model.id }));\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await submit(identity);\n} catch (error) {\n  if (error instanceof Error && error.name === \"PiFormValidationError\") { /* focuses '#pi-provider-base-url' */ return; }\n  throw error;\n}","preventionTips":["Trim the base URL input on blur and disable Save when empty in create mode","Use the exact passthrough key 'baseUrl' (not 'baseURL' or 'url') for per-model overrides","Pre-fill from the preset template so custom presets always carry an endpoint"],"tags":["form-validation","pi","base-url","transport"],"backgroundTag":null,"analyzedSha":"a2e22f330273a5b6ffa87cb8b82b624601bac562","analyzedAt":"2026-08-16T03:46:07.889Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}