mastra-ai/mastra · error

Kimi For Coding token

Error message

Kimi For Coding token ${operation} response missing fields

What it means

credentialsFromTokenResponse validates the fields of a Kimi For Coding token endpoint response (access token, refresh token, finite positive expiresIn). If any required field is missing, empty, wrong type, or the expiry is non-positive, it throws with the operation name (e.g. 'poll' or 'refresh') embedded, indicating the server response did not match the expected token contract.

Solutions

  1. If this happened during polling, ensure the user completed device authorization before the token request succeeds
  2. Re-run the device login flow to obtain fresh tokens if refresh is failing
  3. Log the raw token-endpoint response body to identify which field is missing/wrong
  4. Check for a Kimi API change and update the SDK

Example fix

// before
const creds = await refreshKimiCodingToken(staleCreds); // throws
// after
try {
  creds = await refreshKimiCodingToken(staleCreds);
} catch (err) {
  if (String(err.message).includes('missing fields')) await login('kimi-coding');
  else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the raw token payload yourself before passing it on
function looksLikeTokenPayload(d) {
  return !!d && typeof d === 'object' &&
    typeof d.access_token === 'string' && d.access_token &&
    typeof d.refresh_token === 'string' && d.refresh_token &&
    typeof d.expires_in === 'number' && Number.isFinite(d.expires_in) && d.expires_in > 0;
}

Type guard

function hasTokenFields(d: unknown): d is { access: string; refresh: string; expiresIn: number } {
  const o = d as Record<string, unknown>;
  return typeof o.access === 'string' && !!o.access &&
    typeof o.refresh === 'string' && !!o.refresh &&
    typeof o.expiresIn === 'number' && Number.isFinite(o.expiresIn) && o.expiresIn > 0;
}

Try / catch

try {
  creds = await refreshKimiCodingToken(creds);
} catch (err) {
  if (err instanceof Error && err.message.includes('missing fields')) {
    await login('kimi-coding'); // fall back to a full device login
  } else throw err;
}

Prevention

When it happens

Trigger: During device-login polling (pollKimiCodingTokenOnce) or token refresh (refreshKimiCodingToken), the token endpoint returns JSON lacking access/refresh/expires_in, or with expiresIn <= 0 / non-numeric — e.g. an error envelope, rate-limit body, or API change.

Common situations: Polling before authorization completed and receiving a non-token payload; expired refresh token returning an error object with 200; Kimi API outage or version drift altering field names; proxy injecting error pages with 2xx.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/0605702e93b2c9f1. Report an issue: GitHub.

Appendix: source

Thrown at mastracode/sdk/src/auth/providers/kimi-coding.ts:87

    return null;
  }
}

function credentialsFromTokenResponse(value: unknown, operation: string, deviceId: string): OAuthCredentials {
  const data = (value ?? {}) as Record<string, unknown>;
  const access = data.access_token;
  const refresh = data.refresh_token;
  const expiresIn = data.expires_in;
  if (
    typeof access !== 'string' ||
    !access ||
    typeof refresh !== 'string' ||
    !refresh ||
    typeof expiresIn !== 'number' ||
    !Number.isFinite(expiresIn) ||
    expiresIn <= 0
  ) {
    throw new Error(`Kimi For Coding token ${operation} response missing fields`);
  }
  return { access, refresh, expires: Date.now() + expiresIn * 1000, deviceId };
}

export interface KimiCodingDeviceLoginPending {
  clientId: string;
  deviceId: string;
  deviceCode: string;
  userCode: string;
  url: string;
  instructions: string;
  state: DeviceCodePollState;
}

export type KimiCodingDevicePollResult =
  | { status: 'complete'; credentials: OAuthCredentials }
  | { status: 'pending'; nextPollMs: number; pending: KimiCodingDeviceLoginPending }
  | { status: 'failed'; error: string };

View on GitHub (pinned to 75dd419e61)