coleam00/Archon · error · InvalidProviderKeyError
API key must not be empty.
Error message
API key must not be empty.
What it means
InvalidProviderKeyError thrown by persistProviderApiKey when the submitted API key is empty or whitespace-only. The service trims the input and refuses to encrypt/persist an empty secret, since a stored empty key would be delivered to the provider and fail at call time with a confusing auth error.
Source
Thrown at packages/core/src/credentials/connect-service.ts:62
}
/**
* Validate and store a user's API key for a credential vendor. Accepts legacy
* 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 };View on GitHub (pinned to 0773b97458)
Solutions
- Supply the actual API key string from the provider console before calling persistProviderApiKey.
- Validate client-side that the key field is non-empty (trimmed) before submitting.
- Check the source variable/secret in scripts — an unset env var often interpolates to an empty string.
Example fix
// before
await persistProviderApiKey(userId, 'anthropic', process.env.MY_KEY ?? '');
// after
const key = process.env.MY_KEY?.trim();
if (!key) throw new Error('MY_KEY is not set');
await persistProviderApiKey(userId, 'anthropic', key); Defensive patterns
Strategy: validation
Validate before calling
function canPersistApiKey(apiKey: string): boolean {
return typeof apiKey === 'string' && apiKey.trim().length > 0;
} Try / catch
try {
await persistProviderApiKey(userId, provider, key);
} catch (e) {
if (e instanceof InvalidProviderKeyError && e.message.includes('must not be empty')) {
// prompt user for the key again
} else throw e;
} Prevention
- Require the key field in UI forms (required + minLength validation).
- In scripts, fail on unset env vars: check before interpolating into the connect call.
- Trim and non-empty check the key at every call site boundary.
- Log a clear message when a secret source resolves to empty — never store placeholder values.
When it happens
Trigger: Calling persistProviderApiKey(userId, provider, apiKey) with apiKey = '' or a string of spaces — e.g. an empty form field, an env-var expansion that resolved to nothing, or a client submitting the connect form without pasting a key.
Common situations: Web UI connect form submitted with a blank key field; CI scripting that interpolates an unset secret variable into the connect call; copying a placeholder instead of the real key then trimming it away.
Related errors
- Unknown provider '${provider}'. Known: ${listConnectableVend
- 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/60ef176d02caa83f.
Report an issue: GitHub.