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

  1. Update the AI package to the latest version so the expected response schema matches the provider's current API.
  2. Log the raw initiateResponse body to see what the server actually returned and confirm the schema mismatch.
  3. Check for proxies/captive portals altering the response body.
  4. 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

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


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