can1357/oh-my-pi · error · AIError.OAuthError
Kilo device authorization response missing required fields
Error message
Kilo device authorization response missing required fields
What it means
After the initiation POST succeeds, loginKilo parses the JSON as KiloDeviceAuthCodeResponse and validates that code (userCode), verificationUrl, and expiresIn (a positive number) are all present. If any is missing or malformed, the provider's response doesn't match the expected device-auth contract, and this OAuthError (kind "validation") is thrown instead of continuing with a broken flow.
Source
Thrown at packages/ai/src/registry/kilo.ts:47
throw new AIError.OAuthError("Too many pending authorization requests. Please try again later.", {
kind: "polling",
provider: "kilo",
status: initiateResponse.status,
});
}
throw new AIError.OAuthError(`Failed to initiate device authorization: ${initiateResponse.status}`, {
kind: "device-auth",
provider: "kilo",
status: initiateResponse.status,
});
}
const initiateData = (await initiateResponse.json()) as KiloDeviceAuthCodeResponse;
const userCode = initiateData.code;
const verificationUrl = initiateData.verificationUrl;
const expiresInSeconds = initiateData.expiresIn;
if (!userCode || !verificationUrl || typeof expiresInSeconds !== "number" || expiresInSeconds <= 0) {
throw new AIError.OAuthError("Kilo device authorization response missing required fields", {
kind: "validation",
provider: "kilo",
});
}
callbacks.onAuth?.({
url: verificationUrl,
instructions: `Enter code: ${userCode}`,
});
const deadline = Date.now() + expiresInSeconds * 1000;
while (Date.now() < deadline) {
if (callbacks.signal?.aborted) {
throw new AIError.LoginCancelledError();
}
const pollResponse = await fetchImpl(`${KILO_DEVICE_AUTH_BASE_URL}/codes/${encodeURIComponent(userCode)}`);
if (pollResponse.status === 202) {View on GitHub (pinned to 9690622007)
Solutions
- Update the AI package to the latest version so the expected response schema matches the provider's current API.
- Log the raw initiateResponse body to see what the server actually returned and confirm the schema mismatch.
- Check for proxies/captive portals altering the response body.
- If the server is a custom/staging endpoint, restore it to the documented device-auth response shape ({ code, verificationUrl, expiresIn }).
Example fix
// before
const data = JSON.parse(body); // { verification_url: ... } renamed field -> validation error
// after: update client or map the field
const data = JSON.parse(body);
const normalized = { code: data.code ?? data.device_code, verificationUrl: data.verificationUrl ?? data.verification_url, expiresIn: data.expiresIn ?? data.expires_in }; Defensive patterns
Strategy: validation
Validate before calling
// pre-validate the shape you expect from device-code initiation before handing to the flow
defense: // before calling loginKilo, ensure you're on a current client version
if (!KILO_DEVICE_AUTH_BASE_URL || !KILO_DEVICE_AUTH_BASE_URL.startsWith("https://")) {
throw new Error("Kilo device-auth base URL misconfigured");
} Type guard
function isKiloDeviceAuthResponse(v: unknown): v is KiloDeviceAuthCodeResponse {
const r = v as KiloDeviceAuthCodeResponse;
return typeof r?.code === "string" && r.code.length > 0
&& typeof r?.verificationUrl === "string" && r.verificationUrl.startsWith("https://")
&& typeof r?.expiresIn === "number" && r.expiresIn > 0;
} Try / catch
try {
await loginKilo(callbacks);
} catch (err) {
if (err instanceof AIError.OAuthError && err.message.includes("missing required fields")) {
console.error("Kilo API response shape changed — update the AI package or check for a proxy altering responses");
} else throw err;
} Prevention
- Keep the AI package updated against Kilo API schema changes.
- Bypass suspicious proxies/captive portals when logging in.
- Log raw response bodies on login failure to diagnose contract drift.
- Don't point the client at staging endpoints with different schemas.
When it happens
Trigger: Kilo's device-code endpoint returns 2xx with a JSON body lacking `code`, `verificationUrl`, or a numeric `expiresIn > 0` — e.g. an API schema change, an error payload served with 200, or a truncated/proxied response.
Common situations: Provider API updated its response shape while the client library is outdated; a captive portal or proxy returning HTML with 200 status; intermittent backend bug returning partial payloads; pointing the client at a staging endpoint with a different schema.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Too many pending authorization requests. Please try again la
- Failed to initiate device authorization: ${initiateResponse.
- Login cancelled
- Authorization was denied
- failed to unmarshal LoadCodeAssistResponse: ${result.summary
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f0dda430236b304a.
Report an issue: GitHub.