tinyhumansai/openhuman · warning

Endpoint must start with http:// or https://

Error message

Endpoint must start with http:// or https://

What it means

Custom local-runtime provider save parses the endpoint field with new URL() and requires the protocol to match ^https?:$; explicit non-http schemes like ws://, ftp:// or file:// fail here. A missing scheme never reaches this check — new URL('host:port') throws Invalid URL first. An empty path is then defaulted to /v1.

Source

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

      // /models probe is made — auth + execution both go through the local
      // `claude` CLI. Mirrors the Codex skip, but also skips model listing.
      const isCliLogin = credentialMode === 'cli_login';
      setBusyAction(`toggle-${localLabel ? localLabel.toLowerCase().replace(/\s/g, '') : slug}`);
      // A fresh attempt on THIS provider clears only its own prior advisory —
      // an advisory about a different provider must survive (#5341).
      setProviderSaveNotice(prev => (prev?.slug === slug ? null : prev));

      try {
        const trimmed = value.trim();
        // For `endpoint_key` (OMLX), the endpoint URL arrives via `endpointOverride`
        // (the dialog's endpoint field) and `trimmed` is the API key. For plain
        // `endpoint` runtimes, `trimmed` itself is the endpoint URL.
        const rawEndpoint = isEndpointKey ? (endpointOverride ?? '').trim() : trimmed;
        const endpoint = isLocalRuntime
          ? (() => {
              const url = new URL(rawEndpoint);
              if (!/^https?:$/.test(url.protocol)) {
                throw new Error('Endpoint must start with http:// or https://');
              }
              if (url.pathname === '' || url.pathname === '/') {
                url.pathname = '/v1';
              }
              return url.toString().replace(/\/$/, '');
            })()
          : defaultEndpointFor(slug);

        const upserted: CloudProvider = {
          id: `p_${slug}_${Math.random().toString(36).slice(2, 7)}`,
          slug,
          label: localLabel ?? BUILTIN_PROVIDER_META[slug]?.label ?? slug,
          endpoint,
          authStyle: authStyleForSlug(slug),
          // CLI-login providers hold no API key — reflect that honestly so
          // the entry matches its reloaded (has_api_key === false) shape.
          maskedKey: maskKeyLabel(!isCliLogin),
        };

View on GitHub (pinned to a221052e0d)

Solutions

  1. Use the full http:// or https:// form, e.g. http://localhost:1234/v1
  2. For ws-only servers, enter their plain HTTP base — the /models probe is ordinary HTTP
  3. Omit /v1 if unsure: the code appends /v1 automatically when the path is empty or /

Example fix

// before
endpoint: 'ws://localhost:8080' // throws: protocol not http/https

// after
endpoint: 'http://localhost:8080' // path defaults to /v1
Defensive patterns

Strategy: validation

Validate before calling

const isValidHttpEndpoint = (s: string): boolean => {
  if (!/^https?:\/\//i.test(s.trim())) return false;
  try { new URL(s.trim()); return true; } catch { return false; }
};
if (!isValidHttpEndpoint(input)) { /* block submit with hint */ }

Type guard

const isHttpUrl = (u: URL): boolean => u.protocol === 'http:' || u.protocol === 'https:';

Try / catch

try {
  new URL(rawEndpoint);
} catch {
  // missing scheme lands here as 'Invalid URL' — prompt for http(s):// prefix
}
if (!/^https?:$/.test(new URL(rawEndpoint).protocol)) {
  // non-http scheme — reject with the same guidance
}

Prevention

When it happens

Trigger: Entering ws://localhost:8080, ftp://host, or any explicitly non-http scheme in the local runtime endpoint field; pasting a WebSocket URL for an OpenAI-compatible server.

Common situations: User copies a ws:// URL from server logs, or an internal non-HTTP scheme; missing-scheme typos surface as 'Invalid URL' instead.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/0005fcf9ab0e4cb0. Report an issue: GitHub.