abhigyanpatwari/GitNexus · error
Unsupported local provider: ${provider satisfies never}
Error message
Unsupported local provider: ${provider satisfies never} What it means
Exhaustiveness guard at the end of localModelConfigKey in wiki.ts. The function maps each supported local provider ('cursor' | 'claude' | 'codex' | 'opencode' | 'grok') to its config key; the `provider satisfies never` throw is unreachable for well-typed callers and fires only when a provider string outside the union reaches it (e.g. via untyped JSON, an env var, or a newly added provider missing a mapping).
Source
Thrown at gitnexus/src/cli/wiki.ts:85
function isLocalProvider(
provider: LLMProvider | undefined,
): provider is 'cursor' | 'claude' | 'codex' | 'opencode' | 'grok' {
return (
provider === 'cursor' ||
provider === 'claude' ||
provider === 'codex' ||
provider === 'opencode' ||
provider === 'grok'
);
}
function localModelConfigKey(provider: 'cursor' | 'claude' | 'codex' | 'opencode' | 'grok') {
if (provider === 'cursor') return 'cursorModel';
if (provider === 'claude') return 'claudeModel';
if (provider === 'codex') return 'codexModel';
if (provider === 'opencode') return 'opencodeModel';
if (provider === 'grok') return 'grokModel';
throw new Error(`Unsupported local provider: ${provider satisfies never}`);
}
/**
* Prompt the user for input via stdin.
*/
function prompt(question: string, hide = false): Promise<string> {
return new Promise((resolve) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
if (hide && process.stdin.isTTY) {
// Mask input for API keys
process.stdout.write(question);
let input = '';
process.stdin.setRawMode(true);
process.stdin.resume();View on GitHub (pinned to 52924ef12c)
Solutions
- Correct the provider value to one of: cursor, claude, codex, opencode, grok (exact, lowercase spelling).
- If the value comes from config/JSON, validate it against the allowed provider union before calling.
- If you added a new provider type, extend localModelConfigKey with a mapping branch for it before the throw.
- Let TypeScript check exhaustiveness: keep the parameter typed as the literal union so `satisfies never` fails at compile time, not runtime.
Example fix
// before
function localModelConfigKey(provider: 'cursor' | 'claude' | 'codex' | 'opencode' | 'grok') {
if (provider === 'cursor') return 'cursorModel';
// ... grok mapped, new provider 'windsurf' missing
// after
function localModelConfigKey(provider: 'cursor' | 'claude' | 'codex' | 'opencode' | 'grok' | 'windsurf') {
if (provider === 'cursor') return 'cursorModel';
// ...
if (provider === 'windsurf') return 'windsurfModel';
throw new Error(`Unsupported local provider: ${provider satisfies never}`); Defensive patterns
Strategy: type-guard
Validate before calling
const LOCAL_PROVIDERS = ['cursor', 'claude', 'codex', 'opencode', 'grok'] as const;
type LocalProvider = typeof LOCAL_PROVIDERS[number];
function parseProvider(v: string): LocalProvider {
if (!(LOCAL_PROVIDERS as readonly string[]).includes(v)) {
throw new Error(`Unsupported local provider: ${v}`);
}
return v as LocalProvider;
} Type guard
function isLocalProvider(v: unknown): v is 'cursor' | 'claude' | 'codex' | 'opencode' | 'grok' {
return v === 'cursor' || v === 'claude' || v === 'codex' || v === 'opencode' || v === 'grok';
} Try / catch
try {
const key = localModelConfigKey(provider);
} catch (e) {
if (e.message.startsWith('Unsupported local provider:')) {
console.error(`${e.message} — expected one of cursor, claude, codex, opencode, grok`);
} else throw e;
} Prevention
- Never cast provider strings with `as`; narrow them with a type guard parsed from config/CLI input.
- When adding a provider to the union, extend localModelConfigKey in the same commit — `satisfies never` will flag it at compile time.
- Normalize input (trim, lowercase) before matching provider names.
When it happens
Trigger: Calling localModelConfigKey with a cast/loosely-typed value like `provider as any`, config/CLI input carrying a provider name not in the union (e.g. 'gemini-local'), or a new provider added to a wider type without extending this function's if-chain.
Common situations: Typo in a config file provider field ('claude ' with trailing space, wrong casing), third-party tooling injecting provider strings, or a contributor adding a provider to the wiki command without updating localModelConfigKey.
Related errors
- ${flag} must be a positive integer
- ${flag} is too large
- Wiki was generated in ${prevDisplay}; use --force to regener
- No source files found in the knowledge graph. Nothing to doc
- OpenCode CLI returned no text output
AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-09-01).
Data as JSON: /api/errors/d7d459d7c5d19dbd.
Report an issue: GitHub.