{"record":{"id":"b724bde632396fac","repo":"can1357/oh-my-pi","slug":"providerlabel-login-requires-onprompt-callback","errorCode":null,"errorMessage":"${providerLabel} login requires onPrompt callback","messagePattern":"(.+?) login requires onPrompt callback","errorType":"exception","errorClass":"AIError.OnPromptRequiredError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/registry/api-key-login.ts","lineNumber":61,"sourceCode":"\tproviderLabel: string;\n\t/** URL opened in browser for the user to grab their key, or omitted to skip onAuth. */\n\tauthUrl?: string;\n\t/** Instructions shown with the onAuth callback, or omitted to skip onAuth. */\n\tinstructions?: string;\n\t/** Prompt message shown when asking for the key paste. */\n\tpromptMessage: string;\n\t/** Placeholder string for the prompt (e.g. \"sk-...\", \"csk-...\"). */\n\tplaceholder: string;\n\t/** Validation strategy, or `null` to skip validation. */\n\tvalidation: ChatCompletionsValidation | AnthropicMessagesValidation | ModelsEndpointValidation | null;\n\t/** Value returned for an empty key; also allows an empty prompt response. */\n\temptyKeyFallback?: string;\n};\n\nexport function createApiKeyLogin(config: ApiKeyLoginConfig): (options: OAuthController) => Promise<string> {\n\treturn async function login(options: OAuthController): Promise<string> {\n\t\tif (!options.onPrompt) {\n\t\t\tthrow new AIError.OnPromptRequiredError(config.providerLabel);\n\t\t}\n\n\t\tif (config.authUrl && config.instructions) {\n\t\t\toptions.onAuth?.({\n\t\t\t\turl: config.authUrl,\n\t\t\t\tinstructions: config.instructions,\n\t\t\t});\n\t\t}\n\n\t\tconst apiKey =\n\t\t\tconfig.emptyKeyFallback === undefined\n\t\t\t\t? await options.onPrompt({\n\t\t\t\t\t\tmessage: config.promptMessage,\n\t\t\t\t\t\tplaceholder: config.placeholder,\n\t\t\t\t\t})\n\t\t\t\t: await options.onPrompt({\n\t\t\t\t\t\tmessage: config.promptMessage,\n\t\t\t\t\t\tplaceholder: config.placeholder,","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/registry/api-key-login.ts#L43-L79","documentation":"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').","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass an OAuthController implementing `onPrompt` that collects/returns the API key","Run the login through the interactive CLI which supplies prompt handling","Set the API key directly in provider configuration instead of the interactive login for unattended setups"],"exampleFix":"// before\nawait loginCerebras({});\n// after\nawait loginCerebras({ onPrompt: async q => { showPrompt(q); return apiKey; }, onAuth: a => openBrowser(a.url) });","handlingStrategy":"type-guard","validationCode":"if (typeof options?.onPrompt !== 'function') throw new Error('provider login requires an interactive onPrompt callback');","typeGuard":"function canPrompt(c: OAuthController): c is OAuthController & { onPrompt: NonNullable<OAuthController['onPrompt']> } { return typeof c.onPrompt === 'function'; }","tryCatchPattern":"try { apiKey = await loginBaseten(controller); } catch (e) { if (e instanceof AIError.OnPromptRequiredError) apiKey = await runInteractiveKeyEntry('baseten'); else throw e; }","preventionTips":["Gate provider logins behind an onPrompt existence check","Use one shared OAuthController factory for all providers","In CI, write API keys to config directly and skip login flows"],"tags":["oauth","api-key","interactive-login","configuration"],"backgroundTag":"onprompt-callback-required","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}