coleam00/Archon · error · InvalidProviderKeyError
Unknown provider '${provider}'. Known: ${listConnectableVend
Error message
Unknown provider '${provider}'. Known: ${listConnectableVendors().join(', ')}. What it means
InvalidProviderKeyError thrown by persistProviderApiKey when the provider id (after legacy-alias normalization) is not an api_key-connectable vendor in the catalog. The service fails fast before encrypting and persisting a key it could never deliver, and lists the currently connectable vendors.
Source
Thrown at packages/core/src/credentials/connect-service.ts:66
* agent-keyed ids (`claude`/`codex`/`copilot`) and stores under the
* vendor-canonical id. Throws {@link InvalidProviderKeyError} (before any DB
* write) when the key is blank or the vendor is not in the registry-derived
* connectable catalog; any other throw is a storage failure. The plaintext key
* is encrypted inside the store and is never logged.
*/
export async function persistProviderApiKey(
userId: string,
provider: string,
apiKey: string,
label?: string | null
): Promise<PersistProviderApiKeyResult> {
const trimmedKey = apiKey.trim();
if (!trimmedKey) {
throw new InvalidProviderKeyError('API key must not be empty.');
}
const vendor = normalizeCredentialVendor(provider);
if (!isConnectableVendor(vendor)) {
throw new InvalidProviderKeyError(
`Unknown provider '${provider}'. Known: ${listConnectableVendors().join(', ')}.`
);
}
const normalizedLabel = label?.trim() || null;
await saveUserProviderKey({
userId,
provider: vendor,
kind: 'api_key',
apiKey: trimmedKey,
label: normalizedLabel,
});
// Never log the key value — vendor + user only.
getLog().info({ userId, provider: vendor }, 'provider_api_key.persisted');
return { provider: vendor, kind: 'api_key', label: normalizedLabel };
}
/** Secret-free result of a successful subscription (OAuth) connect. */
export interface PersistProviderOAuthResult {View on GitHub (pinned to 0773b97458)
Solutions
- Use one of the vendors listed in the error (call listConnectableVendors() for the current set).
- Normalize legacy ids via normalizeCredentialVendor before calling, and use vendor-canonical ids ('anthropic', 'openai', 'github-copilot').
- For subscription-only providers (Claude/OpenAI subscriptions), call persistProviderOAuth instead of persistProviderApiKey.
- If a legitimately new vendor is rejected, add its env-var rule to PI_PROVIDER_ENV_VARS (see error 191) — this throw means the catalog cannot deliver it.
- Ensure provider registration (registerBuiltinProviders/registerCommunityProviders) ran before connect.
Example fix
// before await persistProviderApiKey(userId, 'claude-code', key); // after await persistProviderApiKey(userId, 'anthropic', key);
Defensive patterns
Strategy: validation
Validate before calling
import { isConnectableVendor, normalizeCredentialVendor } from './credentials';
function canConnect(id: string): boolean {
return isConnectableVendor(normalizeCredentialVendor(id));
} Try / catch
try {
await persistProviderApiKey(userId, provider, key);
} catch (e) {
if (e instanceof InvalidProviderKeyError && e.message.startsWith('Unknown provider')) {
// show listConnectableVendors() to the user
} else throw e;
} Prevention
- Always pass vendor-canonical ids ('anthropic', 'openai', 'github-copilot'); run normalizeCredentialVendor first.
- Populate provider selectors from listConnectableVendors() rather than hardcoding ids.
- Use subscription login (persistProviderOAuth) for subscription-only vendors.
- Ensure provider registration ran before any connect call in process entrypoints.
When it happens
Trigger: Calling persistProviderApiKey(userId, provider, key) with an unrecognized or non-api-key provider id: a typo ('antropic'), a legacy alias outside {claude, codex, copilot}, an ambient-only vendor (amazon-bedrock), a subscription-only vendor (use persistProviderOAuth instead), or a custom provider that failed to register.
Common situations: Migrating from pre-#1955 agent-keyed ids and using an alias that no longer exists; connecting Bedrock/Vertex via API key when those are ambient-detected; provider registry not bootstrapped (registerBuiltinProviders not run) so the catalog is empty.
Related errors
- API key must not be empty.
- Provider '${provider}' does not support subscription login.
- No chat in context
- Gitea API error: ${String(response.status)} ${response.statu
- Gitea API error: ${String(response.status)}
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/ee75e58bc836315d.
Report an issue: GitHub.