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

xAI device-code response missing or invalid required fields.

Error message

xAI device-code response missing or invalid required fields.

What it means

Thrown by parseXAIDeviceAuthorization when the device-code response is a JSON object but one or more required fields are absent or invalid: device_code, user_code, verification_uri, verification_uri_complete must be non-empty strings, and expires_in/interval must be positive finite numbers. The library needs all of these to run the device login flow, so a partially-formed response is rejected wholesale.

Source

Thrown at packages/ai/src/registry/oauth/xai-oauth.ts:307

	const userCode = typeof payload.user_code === "string" ? payload.user_code.trim() : "";
	const verificationUri = typeof payload.verification_uri === "string" ? payload.verification_uri.trim() : "";
	const verificationUriComplete =
		typeof payload.verification_uri_complete === "string" ? payload.verification_uri_complete.trim() : "";
	const expiresInSeconds = payload.expires_in;
	const intervalSeconds = payload.interval;
	if (
		!deviceCode ||
		!userCode ||
		!verificationUri ||
		!verificationUriComplete ||
		typeof expiresInSeconds !== "number" ||
		!Number.isFinite(expiresInSeconds) ||
		expiresInSeconds <= 0 ||
		typeof intervalSeconds !== "number" ||
		!Number.isFinite(intervalSeconds) ||
		intervalSeconds <= 0
	) {
		throw new AIError.OAuthError("xAI device-code response missing or invalid required fields.", {
			kind: "validation",
			provider: "xai",
		});
	}

	validateXAIEndpoint(verificationUri, "verification_uri");
	validateXAIEndpoint(verificationUriComplete, "verification_uri_complete");
	return {
		deviceCode,
		userCode,
		verificationUriComplete,
		expiresInSeconds,
		intervalSeconds,
	};
}

function parseXAITokenResponse(payload: unknown, label: string, refreshTokenFallback?: string): OAuthCredentials {
	if (!isRecord(payload)) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Log/curl the raw device-code response to see which field is missing or malformed.
  2. Retry the login — an error payload with HTTP 200 usually means a transient xAI-side condition.
  3. Check for proxy/VPN interference that strips or renames response fields.
  4. Update @oh-my-pi/pi-ai — if xAI changed the device-flow field names, a newer package version has the adjusted parser.

Example fix

// before: manually extracting fields from a response you did not validate
const { device_code } = body;
startPolling(device_code);
// after: only proceed when the fields the flow requires are present and typed
if (typeof body.device_code !== "string" || !body.device_code ||
    typeof body.expires_in !== "number" || body.expires_in <= 0) {
  throw new Error("xAI device-code response missing required fields");
}
startPolling(body.device_code);
Defensive patterns

Strategy: validation

Validate before calling

// preflight: verify the device-code response carries the fields the flow needs
const body: Record<string, unknown> = await res.json();
const required = ["device_code", "user_code", "verification_uri", "verification_uri_complete"];
const missing = required.filter((k) => typeof body[k] !== "string" || !(body[k] as string).trim());
if (missing.length > 0 || typeof body.expires_in !== "number" || body.expires_in <= 0 ||
    typeof body.interval !== "number" || body.interval <= 0) {
  console.error("xAI device-code response invalid; fields missing/invalid:", missing, body);
}

Type guard

function isXAIDeviceAuthorization(v: unknown): v is {
  device_code: string; user_code: string; verification_uri: string;
  verification_uri_complete: string; expires_in: number; interval: number;
} {
  if (typeof v !== "object" || v === null) return false;
  const b = v as Record<string, unknown>;
  return typeof b.device_code === "string" && b.device_code.trim() !== "" &&
    typeof b.user_code === "string" && b.user_code.trim() !== "" &&
    typeof b.verification_uri === "string" && b.verification_uri.trim() !== "" &&
    typeof b.verification_uri_complete === "string" && b.verification_uri_complete.trim() !== "" &&
    typeof b.expires_in === "number" && Number.isFinite(b.expires_in) && b.expires_in > 0 &&
    typeof b.interval === "number" && Number.isFinite(b.interval) && b.interval > 0;
}

Try / catch

try {
  const auth = await xaiProvider.device();
  openBrowser(auth.verificationUriComplete);
} catch (err) {
  if (err instanceof AIError.OAuthError && err.kind === "validation" && err.message.includes("missing or invalid required fields")) {
    logger.error("xAI device-code payload incomplete — dump raw response and retry", {});
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: requestXAIDeviceAuthorization receives a 200 JSON object from the xAI device-code endpoint that is missing device_code/user_code/verification_uri/verification_uri_complete, has empty or whitespace-only string values, or has expires_in/interval that are non-numeric, non-finite, or <= 0.

Common situations: xAI returns an error-style payload (e.g. {"error":"access_denied"}) with HTTP 200; a proxy truncates or rewrites fields; xAI renames a field in a API revision; a custom fetchImpl injects defaults that violate the contract.

Related errors


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