{"record":{"id":"0605702e93b2c9f1","repo":"mastra-ai/mastra","slug":"kimi-for-coding-token-operation-response-missin","errorCode":null,"errorMessage":"Kimi For Coding token ${operation} response missing fields","messagePattern":"Kimi For Coding token (.+?) response missing fields","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/auth/providers/kimi-coding.ts","lineNumber":87,"sourceCode":"    return null;\n  }\n}\n\nfunction credentialsFromTokenResponse(value: unknown, operation: string, deviceId: string): OAuthCredentials {\n  const data = (value ?? {}) as Record<string, unknown>;\n  const access = data.access_token;\n  const refresh = data.refresh_token;\n  const expiresIn = data.expires_in;\n  if (\n    typeof access !== 'string' ||\n    !access ||\n    typeof refresh !== 'string' ||\n    !refresh ||\n    typeof expiresIn !== 'number' ||\n    !Number.isFinite(expiresIn) ||\n    expiresIn <= 0\n  ) {\n    throw new Error(`Kimi For Coding token ${operation} response missing fields`);\n  }\n  return { access, refresh, expires: Date.now() + expiresIn * 1000, deviceId };\n}\n\nexport interface KimiCodingDeviceLoginPending {\n  clientId: string;\n  deviceId: string;\n  deviceCode: string;\n  userCode: string;\n  url: string;\n  instructions: string;\n  state: DeviceCodePollState;\n}\n\nexport type KimiCodingDevicePollResult =\n  | { status: 'complete'; credentials: OAuthCredentials }\n  | { status: 'pending'; nextPollMs: number; pending: KimiCodingDeviceLoginPending }\n  | { status: 'failed'; error: string };","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/auth/providers/kimi-coding.ts#L69-L105","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["If this happened during polling, ensure the user completed device authorization before the token request succeeds","Re-run the device login flow to obtain fresh tokens if refresh is failing","Log the raw token-endpoint response body to identify which field is missing/wrong","Check for a Kimi API change and update the SDK"],"exampleFix":"// before\nconst creds = await refreshKimiCodingToken(staleCreds); // throws\n// after\ntry {\n  creds = await refreshKimiCodingToken(staleCreds);\n} catch (err) {\n  if (String(err.message).includes('missing fields')) await login('kimi-coding');\n  else throw err;\n}","handlingStrategy":"try-catch","validationCode":"// Validate the raw token payload yourself before passing it on\nfunction looksLikeTokenPayload(d) {\n  return !!d && typeof d === 'object' &&\n    typeof d.access_token === 'string' && d.access_token &&\n    typeof d.refresh_token === 'string' && d.refresh_token &&\n    typeof d.expires_in === 'number' && Number.isFinite(d.expires_in) && d.expires_in > 0;\n}","typeGuard":"function hasTokenFields(d: unknown): d is { access: string; refresh: string; expiresIn: number } {\n  const o = d as Record<string, unknown>;\n  return typeof o.access === 'string' && !!o.access &&\n    typeof o.refresh === 'string' && !!o.refresh &&\n    typeof o.expiresIn === 'number' && Number.isFinite(o.expiresIn) && o.expiresIn > 0;\n}","tryCatchPattern":"try {\n  creds = await refreshKimiCodingToken(creds);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('missing fields')) {\n    await login('kimi-coding'); // fall back to a full device login\n  } else throw err;\n}","preventionTips":["Refresh tokens before expiry to avoid refresh-endpoint error envelopes","Treat any token-endpoint response failing shape checks as a signal to re-login, not retry blindly","Log the raw response on failure to spot API changes or proxy interference early","Keep the SDK updated for Kimi token API contract changes"],"tags":["auth","oauth","token","schema-validation","kimi-coding"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}