can1357/oh-my-pi · error · AIError.ApiKeyRequiredError

DeepSeek API key is empty after stripping Bearer prefix

Error message

DeepSeek API key is empty after stripping Bearer prefix

What it means

During DeepSeek API-key login, normalizeDeepSeekApiKey() trims the raw key and strips an optional case-insensitive 'Bearer' prefix. If the entire input consisted only of the Bearer prefix (and whitespace), nothing usable remains, so the library throws this ApiKeyRequiredError rather than storing an empty credential. It protects against storing a credential that would fail on every request with an auth error.

Source

Thrown at packages/ai/src/registry/deepseek.ts:26

	authUrl: "https://platform.deepseek.com/api_keys",
	instructions: "Create or copy your API key from the DeepSeek dashboard",
	promptMessage: "Paste your DeepSeek API key",
	placeholder: "sk-...",
	validation: {
		kind: "models-endpoint",
		provider: "deepseek",
		modelsUrl: "https://api.deepseek.com/v1/models",
	},
});

export function normalizeDeepSeekApiKey(raw: string): string {
	const trimmed = raw.trim();
	if (!trimmed) {
		return trimmed;
	}
	const stripped = trimmed.replace(/^bearer\b\s*/i, "");
	if (!stripped) {
		throw new AIError.ApiKeyRequiredError("DeepSeek API key is empty after stripping Bearer prefix");
	}
	return stripped;
}

export const loginDeepSeek = async (options: OAuthController): Promise<string> => {
	const userOnPrompt = options.onPrompt;
	const wrapped: OAuthController = userOnPrompt
		? {
				...options,
				onPrompt: async (prompt: OAuthPrompt) => normalizeDeepSeekApiKey(await userOnPrompt(prompt)),
			}
		: options;
	return innerLogin(wrapped);
};

export const deepseekProvider = {
	id: "deepseek",
	name: "DeepSeek",

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-enter the actual DeepSeek API key (from platform.deepseek.com API keys page) without the Bearer prefix.
  2. If a prefix is included, ensure the key text follows it, e.g. 'Bearer sk-xxxx'.
  3. Check clipboard/paste — re-copy the full key and confirm it starts with 'sk-'.
  4. Verify the input source (file/stdin/env) actually contains the key, not just the header token.

Example fix

// before
await loginDeepSeek({ onPrompt: async () => "Bearer" });
// throws ApiKeyRequiredError
// after
await loginDeepSeek({ onPrompt: async () => "Bearer sk-abc123..." });
// or simply:
await loginDeepSeek({ onPrompt: async () => "sk-abc123..." });
Defensive patterns

Strategy: validation

Validate before calling

// sanitize before passing the key into login
const raw = userInput.trim();
const key = /^bearer\b\s*/i.test(raw) ? raw.replace(/^bearer\b\s*/i, "") : raw;
if (!key) throw new Error("Paste the DeepSeek key itself, not just the 'Bearer' prefix");

Type guard

function isUsableApiKey(v: unknown): v is string {
  return typeof v === "string" && v.trim().replace(/^bearer\b\s*/i, "").length > 0;
}

Try / catch

try {
  await loginDeepSeek({ onPrompt: promptForKey });
} catch (err) {
  if (err instanceof AIError.ApiKeyRequiredError) {
    console.error("Input contained only a Bearer prefix — paste the full sk-... key");
  } else throw err;
}

Prevention

When it happens

Trigger: Invoking loginDeepSeek (or any path calling normalizeDeepSeekApiKey) with a raw key string that, after trimming and removing the leading 'Bearer' token, is empty — e.g. the input is exactly "Bearer", "bearer ", or only whitespace fails the earlier empty check and reaches the strip check only when a prefix is present.

Common situations: Pasting just the header line 'Bearer' from a curl example instead of the key; clipboard capture grabbing a truncated paste; scripts piping a token file that contains only the prefix; IDE/auto-complete inserting 'Bearer ' before an empty field.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/98a4a40016e52a00. Report an issue: GitHub.