{"record":{"id":"054f14cfa2d22243","repo":"tinyhumansai/openhuman","slug":"settings-ai-slugmissingerror-settings-ai-sluginu","errorCode":null,"errorMessage":"settings.ai.slugMissingError | settings.ai.slugInUseError | settings.ai.slugReservedError","messagePattern":"settings\\.ai\\.slugMissingError \\| settings\\.ai\\.slugInUseError \\| settings\\.ai\\.slugReservedError","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/src/components/settings/panels/AIPanel.tsx","lineNumber":3906,"sourceCode":"  // Skipping verification is a bet that the provider works despite an\n  // unreadable listing. For an Azure host that is not the `/openai/v1` base\n  // that bet is already lost: `{base}/chat/completions` is not a route Azure\n  // serves there and the stored bearer auth is the wrong header, so the entry\n  // would be dead on arrival. Withhold the bypass and let the inline nudge do\n  // its job instead of manufacturing a broken provider (#5213).\n  const knownUnusableEndpoint =\n    isAzureFoundryEndpoint(endpoint) && !isAzureV1BaseUrl(endpoint.trim());\n\n  const submitProvider = async (opts?: { skipProbe?: boolean }) => {\n    setSaving(true);\n    setSubmitError(null);\n    // Cleared alongside the error: a later attempt that fails for an unrelated\n    // reason (slug collision, key write) must not still offer to skip\n    // verification, which is the distinction `ProviderProbeError` exists for.\n    setProbeFailed(false);\n    try {\n      if (slugError) {\n        throw new Error(slugError);\n      }\n      await onSubmit(\n        {\n          id: initial?.id ?? '',\n          slug,\n          label: label.trim() || slug,\n          endpoint: endpoint.trim(),\n          authStyle: initial?.authStyle ?? 'bearer',\n          maskedKey: maskKeyLabel(hasExistingKey || apiKey.length > 0),\n        },\n        apiKey.trim(),\n        opts\n      );\n    } catch (err) {\n      // Surface the failure inline and keep the dialog open so the user can fix\n      // the key/URL and retry. A rejected `/models` probe additionally unlocks\n      // the \"add without verifying\" button — the listing is a convenience for\n      // the model dropdown, not a precondition for inference.","sourceCodeStart":3888,"sourceCodeEnd":3924,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/components/settings/panels/AIPanel.tsx#L3888-L3924","documentation":"submitProvider re-throws a precomputed slugError before doing anything else: the custom provider slug must be non-empty (slugMissingError), must not collide with another provider's slug (slugInUseError), and — when creating, not editing — must not match a builtin (slugReservedError, from BUILTIN_RESERVED_SLUGS).","triggerScenarios":"Submitting the custom-provider form with an empty slug, a slug already used by an existing entry, or a slug matching a reserved builtin name.","commonSituations":"User duplicates an existing provider config and forgets to rename the slug; tries to shadow a builtin provider by reusing its slug.","solutions":["Enter a unique, non-empty slug that does not match a builtin provider name","Rename or delete the colliding custom provider first","Check the live slugError indicator next to the field before submitting"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Compute the same three checks before enabling submit:\nconst slugOk =\n  slug.trim().length > 0 &&\n  !existingSlugs.includes(slug) &&\n  (isEditing || !BUILTIN_RESERVED_SLUGS.includes(slug));\nif (!slugOk) { /* disable submit and show which rule failed */ }","typeGuard":"const isUsableSlug = (\n  slug: string,\n  existing: readonly string[],\n  reserved: readonly string[],\n  isEdit: boolean\n): boolean =>\n  slug.trim().length > 0 &&\n  !existing.includes(slug) &&\n  (isEdit || !reserved.includes(slug));","tryCatchPattern":"try {\n  await submitProvider({ skipProbe });\n} catch (e) {\n  if (e instanceof Error && e.message === slugError) {\n    // keep dialog open focused on the slug field\n    return;\n  }\n  throw e;\n}","preventionTips":["Show the reserved-slug list (or autocomplete around it) in the form UI","Auto-suggest a slug derived from the label, checked for uniqueness live","Remember reserved-slug collision only applies when creating, not editing"],"tags":["validation","slug","custom-provider","settings"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}