tinyhumansai/openhuman · error · Error

settings.ai.slugMissingError|settings.ai.slugInUseError|sett

Error message

settings.ai.slugMissingError|settings.ai.slugInUseError|settings.ai.slugReservedError

What it means

submitProvider throws a precomputed slugError before ever calling onSubmit. slugError is derived in three ordered steps (AIPanel.tsx:3880-3886): slug empty (label slugifies to nothing) -> settings.ai.slugMissingError; slug already present in existingSlugs -> settings.ai.slugInUseError; adding (not editing, !initial) a slug in BUILTIN_RESERVED_SLUGS -> settings.ai.slugReservedError. The same slugError is rendered inline under the field and disables the Save button, so this throw only fires on programmatic submits or racing state.

Source

Thrown at app/src/components/settings/panels/AIPanel.tsx:3906

  // Skipping verification is a bet that the provider works despite an
  // unreadable listing. For an Azure host that is not the `/openai/v1` base
  // that bet is already lost: `{base}/chat/completions` is not a route Azure
  // serves there and the stored bearer auth is the wrong header, so the entry
  // would be dead on arrival. Withhold the bypass and let the inline nudge do
  // its job instead of manufacturing a broken provider (#5213).
  const knownUnusableEndpoint =
    isAzureFoundryEndpoint(endpoint) && !isAzureV1BaseUrl(endpoint.trim());

  const submitProvider = async (opts?: { skipProbe?: boolean }) => {
    setSaving(true);
    setSubmitError(null);
    // Cleared alongside the error: a later attempt that fails for an unrelated
    // reason (slug collision, key write) must not still offer to skip
    // verification, which is the distinction `ProviderProbeError` exists for.
    setProbeFailed(false);
    try {
      if (slugError) {
        throw new Error(slugError);
      }
      await onSubmit(
        {
          id: initial?.id ?? '',
          slug,
          label: label.trim() || slug,
          endpoint: endpoint.trim(),
          authStyle: initial?.authStyle ?? 'bearer',
          maskedKey: maskKeyLabel(hasExistingKey || apiKey.length > 0),
        },
        apiKey.trim(),
        opts
      );
    } catch (err) {
      // Surface the failure inline and keep the dialog open so the user can fix
      // the key/URL and retry. A rejected `/models` probe additionally unlocks
      // the "add without verifying" button — the listing is a convenience for
      // the model dropdown, not a precondition for inference.

View on GitHub (pinned to 7491200858)

Solutions

  1. Change the label so its slug differs - add a distinguishing word or number
  2. To configure a built-in provider, edit the built-in entry instead of creating a custom one with its slug
  3. When editing an existing entry, the reserved check no longer applies - only emptiness and duplicates do
  4. If hit programmatically, compute slugifyCustomProviderName(label) first and assert it is non-empty and unused

Example fix

// before - rely on the throw inside submitProvider
await submitProvider();

// after - gate the call on the same conditions the form uses
const slug = slugifyCustomProviderName(label);
if (!slug || existingSlugs.includes(slug) || (!initial && BUILTIN_RESERVED_SLUGS.includes(slug))) {
  return; // field-level slugError already tells the user why
}
await submitProvider();
Defensive patterns

Strategy: validation

Validate before calling

// Reproduce the form's gate before submitting programmatically
const slug = slugifyCustomProviderName(label);
const slugError = !slug
  ? t('settings.ai.slugMissingError')
  : existingSlugs.includes(slug)
    ? t('settings.ai.slugInUseError')
    : !initial && BUILTIN_RESERVED_SLUGS.includes(slug)
      ? t('settings.ai.slugReservedError')
      : null;
if (slugError) { setSubmitError(slugError); return; }

Prevention

When it happens

Trigger: A custom-provider label whose slugified form is empty (label is only emoji/punctuation/spaces); a label that slugifies identically to an existing custom provider's slug; or creating a new custom provider whose label collides with a built-in slug (e.g. 'openai') - reserved check is skipped when editing an existing entry.

Common situations: Users naming a provider 'OpenAI' or 'Anthropic' trying to override a built-in; two providers named 'My GPT' and 'my-gpt'; labels in scripts/emoji that produce no slug characters; UI state where the inline error is set but the disabled Save is bypassed (double-click race before re-render).

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/46ed6363a03f2172. Report an issue: GitHub.