{"record":{"id":"90a7d3f0adb6ecc4","repo":"farion1231/cc-switch","slug":"model-id-needs-a-base-url-either-directly-or","errorCode":null,"errorMessage":"Model {{id}} needs a base URL, either directly or from the provider","messagePattern":"Model (.+?)\\} needs a base URL, either directly or from the provider","errorType":"validation","errorClass":"PiFormValidationError","httpStatus":null,"severity":"error","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/0b5da510168914b251481654a568c3ffacd62cf4/src/components/providers/forms/PiProviderForm.tsx#L1171-L1207","documentation":"Companion to the API check: PiProviderForm computes effectiveUrl = model's passthrough baseUrl override (trimmed) || provider-level baseUrl (trimmed) and, in create mode, throws pi.form.effectiveBaseUrlRequired (with the model id, focusing #pi-provider-base-url) when it is empty. Without a base URL, custom (non-built-in) providers have no endpoint to send requests to. Edit mode is exempt for the same partial-override reason as the API check.","triggerScenarios":"Creating a custom provider without filling the Base URL field while none of the models carry a baseUrl passthrough; whitespace-only base URL (it is trimmed, so '   ' counts as empty); preset switched to custom wiped the URL.","commonSituations":"User expects preset defaults to apply in the custom path; proxy/gateway deployments where the URL was meant to be added later; trailing-space paste making the field look filled.","solutions":["Enter the provider endpoint in the Base URL field, e.g. 'https://api.example.com/v1' (leading/trailing spaces are trimmed away).","If only one model needs a different endpoint, set its per-model baseUrl passthrough instead of the provider-level field.","Confirm no whitespace-only value is lingering in the field after paste."],"exampleFix":"// before\nconst baseUrl = \"   \"; // looks filled, trims to empty\nconst model = { id: \"m1\", passthrough: {} };\nsubmit(identity); // throws \"Model m1 needs a base URL, ...\"\n\n// after\nconst baseUrl = \"https://api.example.com/v1\";\nsubmit(identity);","handlingStrategy":"validation","validationCode":"const effectiveUrl = (typeof model.passthrough.baseUrl === \"string\" ? model.passthrough.baseUrl.trim() : \"\") || baseUrl.trim();\nif (!isEdit && !effectiveUrl) highlight(\"#pi-provider-base-url\", \"Base URL is required\");","typeGuard":"const hasBaseUrl = (m: ModelRow): boolean => (typeof m.passthrough.baseUrl === \"string\" && m.passthrough.baseUrl.trim().length > 0) || baseUrl.trim().length > 0;","tryCatchPattern":"catch (e) {\n  if (e instanceof PiFormValidationError && e.fieldSelector === \"#pi-provider-base-url\") { setFormError(e.message); document.querySelector(e.fieldSelector)?.focus(); return; }\n  throw e;\n}","preventionTips":["Trim the base URL field on blur so whitespace-only values show as empty.","Require the URL field whenever the custom (non-preset) path is active."],"tags":["pi","form-validation","base-url","transport-config"],"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"}