jlcodes99/cockpit-tools · error

API_KEY_REQUIRED

API_KEY_REQUIRED

Error message

API_KEY_REQUIRED

What it means

updateApiKeyOnCodexModelProvider sanitizes the supplied secret with sanitizeApiKey and throws API_KEY_REQUIRED when the normalized value is empty — i.e. the call would replace the key with nothing. This is an input-validation guard executed before the provider lookup, so an empty key never reaches the store.

Source

Thrown at src/services/codexModelProviderService.ts:815

  if (!apiKey) throw new Error('API_KEY_NOT_FOUND');

  const now = Date.now();
  apiKey.name = sanitizeName(name);
  apiKey.updatedAt = now;
  provider.updatedAt = now;
  await writeProviders(providers);
  return { ...provider, apiKeys: provider.apiKeys.map((item) => ({ ...item })) };
}

/** Replace the secret for an existing provider API key without changing its id. */
export async function updateApiKeyOnCodexModelProvider(
  providerId: string,
  apiKeyId: string,
  apiKey: string,
  name?: string,
): Promise<CodexModelProvider> {
  const normalizedApiKey = sanitizeApiKey(apiKey);
  if (!normalizedApiKey) throw new Error("API_KEY_REQUIRED");

  const providers = await ensureProvidersLoaded();
  const provider = providers.find((item) => item.id === providerId);
  if (!provider) throw new Error("PROVIDER_NOT_FOUND");
  const existing = provider.apiKeys.find((item) => item.id === apiKeyId);
  if (!existing) throw new Error("API_KEY_NOT_FOUND");

  const duplicate = provider.apiKeys.some(
    (item) => item.id !== apiKeyId && sanitizeApiKey(item.apiKey) === normalizedApiKey,
  );
  if (duplicate) throw new Error("API_KEY_EXISTS");

  const now = Date.now();
  existing.apiKey = normalizedApiKey;
  if (name !== undefined) {
    existing.name = sanitizeName(name);
  }
  existing.updatedAt = now;

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Ensure a non-empty key is passed: check apiKey.trim().length > 0 before calling.
  2. Fix the source of the empty value (set the env var, correct the config path, re-copy the secret).
  3. If you meant to delete the key, use removeApiKeyFromCodexModelProvider instead of updating to an empty value.
  4. Catch 'API_KEY_REQUIRED' and show a 'key must not be empty' prompt in the UI.

Example fix

// before
await updateApiKeyOnCodexModelProvider(providerId, keyId, process.env.NEW_KEY ?? '');
// after
const key = process.env.NEW_KEY;
if (!key || !key.trim()) throw new Error('NEW_KEY must be set to rotate the API key');
await updateApiKeyOnCodexModelProvider(providerId, keyId, key.trim());
Defensive patterns

Strategy: validation

Validate before calling

const key = (apiKey ?? '').trim();
if (!key) throw new Error('API_KEY_REQUIRED: new key material must be non-empty');

Type guard

function isNonEmptySecret(value: unknown): value is string {
  return typeof value === 'string' && value.trim().length > 0;
}

Try / catch

try {
  await updateApiKeyOnCodexModelProvider(providerId, apiKeyId, apiKey, name);
} catch (e) {
  if ((e as Error).message === 'API_KEY_REQUIRED') {
    showFieldError('apiKey', 'Enter the new API key value');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling updateApiKeyOnCodexModelProvider(providerId, apiKeyId, apiKey, name?) where sanitizeApiKey(apiKey) returns '' — apiKey is '', whitespace, undefined-as-string, or a value stripped entirely by sanitization (e.g. only characters the sanitizer removes).

Common situations: Rotating a key but pasting an empty clipboard; an env var (e.g. PROVIDER_API_KEY) unset so the code passes an empty string; form field cleared then saved; reading the key from a config that returns null coerced to ''.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/a41227771de70f57. Report an issue: GitHub.