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

${providerLabel} login requires onPrompt callback

Error message

${providerLabel} login requires onPrompt callback

What it means

createApiKeyLogin is a factory for API-key login flows. Each generated login function requires an onPrompt callback on the OAuthController to ask the user for the API key (and optionally show an auth URL/instructions). If onPrompt is missing, the generated login throws OnPromptRequiredError labeled with the provider (e.g. 'Cerebras login requires onPrompt callback').

Source

Thrown at packages/ai/src/registry/api-key-login.ts:61

	providerLabel: string;
	/** URL opened in browser for the user to grab their key, or omitted to skip onAuth. */
	authUrl?: string;
	/** Instructions shown with the onAuth callback, or omitted to skip onAuth. */
	instructions?: string;
	/** Prompt message shown when asking for the key paste. */
	promptMessage: string;
	/** Placeholder string for the prompt (e.g. "sk-...", "csk-..."). */
	placeholder: string;
	/** Validation strategy, or `null` to skip validation. */
	validation: ChatCompletionsValidation | AnthropicMessagesValidation | ModelsEndpointValidation | null;
	/** Value returned for an empty key; also allows an empty prompt response. */
	emptyKeyFallback?: string;
};

export function createApiKeyLogin(config: ApiKeyLoginConfig): (options: OAuthController) => Promise<string> {
	return async function login(options: OAuthController): Promise<string> {
		if (!options.onPrompt) {
			throw new AIError.OnPromptRequiredError(config.providerLabel);
		}

		if (config.authUrl && config.instructions) {
			options.onAuth?.({
				url: config.authUrl,
				instructions: config.instructions,
			});
		}

		const apiKey =
			config.emptyKeyFallback === undefined
				? await options.onPrompt({
						message: config.promptMessage,
						placeholder: config.placeholder,
					})
				: await options.onPrompt({
						message: config.promptMessage,
						placeholder: config.placeholder,

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass an OAuthController implementing `onPrompt` that collects/returns the API key
  2. Run the login through the interactive CLI which supplies prompt handling
  3. Set the API key directly in provider configuration instead of the interactive login for unattended setups

Example fix

// before
await loginCerebras({});
// after
await loginCerebras({ onPrompt: async q => { showPrompt(q); return apiKey; }, onAuth: a => openBrowser(a.url) });
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof options?.onPrompt !== 'function') throw new Error('provider login requires an interactive onPrompt callback');

Type guard

function canPrompt(c: OAuthController): c is OAuthController & { onPrompt: NonNullable<OAuthController['onPrompt']> } { return typeof c.onPrompt === 'function'; }

Try / catch

try { apiKey = await loginBaseten(controller); } catch (e) { if (e instanceof AIError.OnPromptRequiredError) apiKey = await runInteractiveKeyEntry('baseten'); else throw e; }

Prevention

When it happens

Trigger: Calling any login created by createApiKeyLogin (loginAiand, loginBaseten, loginCerebras, loginClinePass, loginCoreWeave, loginDeepinfra, etc.) with an options object that has no `onPrompt` function — typical in headless scripts or minimally-constructed controllers.

Common situations: Automated credential provisioning; embedding provider login in a custom CLI without prompt UI; non-TTY environments; refactoring that dropped the prompt hooks from the controller.

Related errors


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