can1357/oh-my-pi · error · AIError.OnPromptRequiredError
Xiaomi Token Plan (${TOKEN_PLAN_REGION_NAMES[region]})
Error message
Xiaomi Token Plan (${TOKEN_PLAN_REGION_NAMES[region]}) What it means
loginXiaomiTokenPlan performs interactive OAuth-style login for Xiaomi's token plan. The library requires a prompt callback so the caller can collect the API key from the user; if the OAuthController has no onPrompt, it aborts with OnPromptRequiredError before doing any network work. This is a programming/configuration error in the caller, not a runtime condition.
Source
Thrown at packages/ai/src/registry/oauth/xiaomi.ts:190
const trimmed = apiKey.trim();
if (!trimmed) {
throw new AIError.ApiKeyRequiredError();
}
options.onProgress?.(`Validating ${PROVIDER_ID} API key...`);
await validateXiaomiApiKey(trimmed, undefined, options.signal, fetchImpl);
return trimmed;
}
/**
* Login to a regional Xiaomi Token Plan endpoint.
*
* Prompts for a token-plan API key and validates it against the selected region.
*/
export async function loginXiaomiTokenPlan(options: OAuthController, region: XiaomiTokenPlanRegion): Promise<string> {
const fetchImpl = options.fetch ?? fetch;
if (!options.onPrompt) {
throw new AIError.OnPromptRequiredError(`Xiaomi Token Plan (${TOKEN_PLAN_REGION_NAMES[region]})`);
}
options.onAuth?.({
url: TOKEN_PLAN_AUTH_URL,
instructions: `Copy your token-plan API key for the ${TOKEN_PLAN_REGION_NAMES[region]} region`,
});
const apiKey = await options.onPrompt({
message: `Paste your Xiaomi Token Plan ${TOKEN_PLAN_REGION_NAMES[region]} API key (tp-...)`,
placeholder: "tp-...",
});
if (options.signal?.aborted) {
throw new AIError.LoginCancelledError();
}
const trimmed = apiKey.trim();
if (!trimmed) {
throw new AIError.ApiKeyRequiredError();
}
options.onProgress?.(`Validating Xiaomi Token Plan (${TOKEN_PLAN_REGION_NAMES[region]}) API key...`);View on GitHub (pinned to 9690622007)
Solutions
- Provide an onPrompt callback on the OAuthController that surfaces a text input to the user and resolves with the pasted tp-... API key.
- If no interaction is possible, bypass loginXiaomiTokenPlan and configure the API key directly via the provider's api-key entry path.
- Detect non-interactive environments up front and catch OnPromptRequiredError to report that interactive login is unavailable.
Example fix
// before
await loginXiaomiTokenPlan({ signal, fetch }, "cn");
// after
await loginXiaomiTokenPlan({ signal, fetch, onPrompt: async opts => window.prompt(opts.message) ?? "" }, "cn"); Defensive patterns
Strategy: try-catch
Validate before calling
if (typeof controller.onPrompt !== "function") throw new Error("Interactive Xiaomi login requires an onPrompt callback"); Type guard
function canPrompt(c): c is typeof c & { onPrompt: (o: { message: string; placeholder?: string }) => Promise<string> } { return typeof c.onPrompt === "function"; } Try / catch
try { await loginXiaomiTokenPlan(controller, region); }
catch (e) { if (e instanceof AIError.OnPromptRequiredError) { console.error("Interactive login unavailable; set the API key directly."); return; } throw e; } Prevention
- Always wire onPrompt before invoking any OAuth login function
- Detect non-TTY/headless environments early and use direct API-key configuration instead
- Keep the OAuthController construction centralized so callbacks are never omitted
When it happens
Trigger: loginXiaomiTokenPlan (or one of the region providers xiaomiTokenPlanAms/Cn/SgpProvider) is invoked with an OAuthController that lacks an onPrompt function, e.g. headless/SDK usage that only sets fetch or onProgress.
Common situations: Embedding the login flow in a script or CI job with no TTY; constructing the controller without wiring the UI callback; running in a non-interactive environment where the app skips prompt registration.
Related errors
- Alibaba Coding Plan
- QwenCloud Token Plan
- ${providerLabel} login requires onPrompt callback
- No OAuth credential available for provider: ${provider}
- OAuth refresh ownership aborted by caller
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/4f13a785d5be4c7d.
Report an issue: GitHub.