github/spec-kit · error · ValueError
providers[{i}]: invalid host pattern {h!r}. Only exact hostn
Error message
providers[{i}]: invalid host pattern {h!r}. Only exact hostnames or '*.suffix' forms are allowed (e.g. 'github.com' or '*.visualstudio.com'). What it means
Raised while parsing the `providers` array in the auth config when a `hosts` entry fails the `_is_valid_host_pattern` check. Only exact hostnames (e.g. `github.com`) or single-label `*.suffix` wildcards (e.g. `*.visualstudio.com`) are accepted; broader wildcards like `*github.com`, `*.`, or hosts containing scheme/path characters are rejected because they can match attacker-controlled domains (e.g. `*github.com` also matches `github.com.evil.com`).
Source
Thrown at src/specify_cli/authentication/config.py:139
if not isinstance(providers_raw, list):
raise ValueError("auth.json must contain a 'providers' array")
entries: list[AuthConfigEntry] = []
for i, entry_raw in enumerate(providers_raw):
if not isinstance(entry_raw, dict):
raise ValueError(f"providers[{i}]: must be a JSON object")
hosts = entry_raw.get("hosts")
if not isinstance(hosts, list) or not hosts:
raise ValueError(f"providers[{i}]: 'hosts' must be a non-empty array")
if not all(isinstance(h, str) and h.strip() for h in hosts):
raise ValueError(f"providers[{i}]: each host must be a non-empty string")
# Normalize hosts: strip whitespace and lowercase
hosts = [h.strip().lower() for h in hosts]
# Reject dangerous wildcard forms (e.g. *github.com matches github.com.evil.com)
for h in hosts:
if not _is_valid_host_pattern(h):
raise ValueError(
f"providers[{i}]: invalid host pattern {h!r}. "
"Only exact hostnames or '*.suffix' forms are allowed "
"(e.g. 'github.com' or '*.visualstudio.com')."
)
provider = entry_raw.get("provider", "")
if not isinstance(provider, str) or not provider:
raise ValueError(f"providers[{i}]: 'provider' must be a non-empty string")
auth = entry_raw.get("auth", "")
if not isinstance(auth, str) or not auth:
raise ValueError(f"providers[{i}]: 'auth' must be a non-empty string")
token = entry_raw.get("token")
token_env = entry_raw.get("token_env")
# Validate token/token_env types
if token is not None and (not isinstance(token, str) or not token.strip()):View on GitHub (pinned to bf88c9f9a8)
Solutions
- Use an exact hostname (e.g. `github.com`) or a single `*.suffix` wildcard (e.g. `*.visualstudio.com`)
- Remove scheme/path portions from the host string — hosts are bare hostnames only
- List each deeper subdomain explicitly instead of multi-level wildcards
Example fix
// before "hosts": ["*github.com", "https://git.example.com"] // after "hosts": ["github.com", "git.example.com"]
Defensive patterns
Strategy: validation
Validate before calling
import re
_HOST_EXACT = re.compile(r"^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$")
def is_valid_host_pattern(h: str) -> bool:
h = h.strip().lower()
if h.startswith("*."):
return bool(_HOST_EXACT.match(h[2:]))
return bool(_HOST_EXACT.match(h)) Type guard
def is_host_pattern_list(value: object) -> bool:
return (
isinstance(value, list)
and bool(value)
and all(isinstance(h, str) and is_valid_host_pattern(h) for h in value)
) Try / catch
try:
load_auth_config(raw)
except ValueError as exc:
if "invalid host pattern" in str(exc):
# surface the offending host from the message and fix the config source
raise SystemExit(f"Fix auth config: {exc}") from exc
raise Prevention
- Lint the auth config in CI with a schema check that validates hosts against exact-or-*.suffix patterns
- Never paste URLs into hosts — strip scheme and path first
- Remember hosts are lowercased and stripped automatically, so only structure can fail
When it happens
Trigger: An entry in the `providers` JSON/YAML list contains a host string that is neither a plain hostname nor a `*.suffix` pattern — e.g. `"*github.com"`, `"https://github.com"`, `"*"`, `"github.com/*"`, or `"*.*.com"`. Hosts are stripped and lowercased before the check, so whitespace/case never trigger it.
Common situations: Copying a CORS-style or cookies-style wildcard from another tool's config; pasting a full URL instead of a hostname; trying to match all subdomains in depth with `**.` or nested wildcards.
Related errors
- providers[{i}]: 'provider' must be a non-empty string
- providers[{i}]: 'auth' must be a non-empty string
- providers[{i}]: 'token' must be a non-empty string
- providers[{i}]: 'token_env' must be a non-empty string
- providers[{i}]: unknown provider {provider!r}; registered: {
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/a6bc60b433dee501.
Report an issue: GitHub.