{"record":{"id":"807225d591bfb7ec","repo":"mastra-ai/mastra","slug":"invalid-device-code-response-fields","errorCode":null,"errorMessage":"Invalid device code response fields","messagePattern":"Invalid device code response fields","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/auth/providers/github-copilot.ts","lineNumber":156,"sourceCode":"  if (!data || typeof data !== 'object') {\n    throw new Error('Invalid device code response');\n  }\n\n  const obj = data as Record<string, unknown>;\n  const deviceCode = obj.device_code;\n  const userCode = obj.user_code;\n  const verificationUri = obj.verification_uri;\n  const interval = obj.interval;\n  const expiresIn = obj.expires_in;\n\n  if (\n    typeof deviceCode !== 'string' ||\n    typeof userCode !== 'string' ||\n    typeof verificationUri !== 'string' ||\n    typeof interval !== 'number' ||\n    typeof expiresIn !== 'number'\n  ) {\n    throw new Error('Invalid device code response fields');\n  }\n\n  return {\n    device_code: deviceCode,\n    user_code: userCode,\n    verification_uri: verificationUri,\n    interval,\n    expires_in: expiresIn,\n  };\n}\n\n/** Sleep that can be interrupted by an AbortSignal. */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n  return new Promise((resolve, reject) => {\n    if (signal?.aborted) {\n      reject(new Error('Login cancelled'));\n      return;\n    }","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/auth/providers/github-copilot.ts#L138-L174","documentation":"After the device-code response parsed as an object, `startDeviceFlow` checks that `device_code`, `user_code`, `verification_uri` are strings and `interval`, `expires_in` are numbers. A missing or mistyped field means GitHub answered ok but the payload is not a valid device-code response, so the SDK refuses to continue the polling flow. This is a defensive schema validation against contract drift or non-GitHub responses.","triggerScenarios":"GitHub returns an object without the standard device-flow fields — e.g. an error object like `{error:\"...\", error_description:\"...\"}` delivered with a 200, a GHES instance with a divergent device-flow implementation, or an API version change renaming/omitting fields.","commonSituations":"GHES or GitHub proxy endpoints with older/newer device-flow implementations, interception by a mock or gateway returning partial JSON, GitHub deprecating/changing field types in a future API version.","solutions":["Inspect the actual response object (log it before this call) to see which field is missing or mistyped","Confirm the domain points at a real GitHub/GHES device-flow endpoint, not a proxy or mock","Check for an error object in the response (`error`, `error_description`) and surface that message instead","Upgrade the SDK — field validation may need updating after a GitHub API change","File/verify against GHES release notes if using GitHub Enterprise Server, as its device-flow payload can lag github.com"],"exampleFix":"// before: swallowing the real payload\nconst d = await provider.device(); // throws 'Invalid device code response fields'\n// after: capture and inspect the raw response to see the real error\nconst raw = await fetch(deviceCodeUrl, { method: 'POST', ... });\nconst body = await raw.json();\nif (body.error) throw new Error(`GitHub: ${body.error} - ${body.error_description}`);\nconsole.log(body); // then compare with expected device_code/user_code fields","handlingStrategy":"type-guard","validationCode":"// Validate the raw device-flow payload shape yourself before/alongside the SDK call\nfunction looksLikeDeviceCode(o: unknown): boolean {\n  return !!o && typeof o === 'object' && ['device_code','user_code','verification_uri','interval','expires_in'].every(k => k in (o as Record<string, unknown>));\n}","typeGuard":"function isValidDeviceCodeFields(v: unknown): v is { device_code: string; user_code: string; verification_uri: string; interval: number; expires_in: number } {\n  if (!v || typeof v !== 'object') return false;\n  const o = v as Record<string, unknown>;\n  return typeof o.device_code === 'string'\n    && typeof o.user_code === 'string'\n    && typeof o.verification_uri === 'string'\n    && typeof o.interval === 'number'\n    && typeof o.expires_in === 'number';\n}","tryCatchPattern":"try {\n  const pending = await provider.device();\n} catch (e) {\n  if (e instanceof Error && e.message === 'Invalid device code response fields') {\n    // Surface the raw payload to see the actual error envelope or field drift\n    const raw = await fetchRawDeviceCode(); // your own diagnostic call\n    if (raw && typeof raw === 'object' && 'error' in (raw as object)) {\n      throw new Error(`GitHub device flow: ${(raw as any).error} - ${(raw as any).error_description}`);\n    }\n    throw new Error(`Device-code fields missing/mistyped: ${JSON.stringify(raw)}`);\n  }\n  throw e;\n}","preventionTips":["Inspect the raw response when this fires — often it is an OAuth error object served with 200","Keep the SDK updated so field validation tracks GitHub API changes","Use real GitHub endpoints in dev; incomplete MSW/mocks cause this validation to trip","On GHES, verify the instance's device-flow implementation returns all five standard fields"],"tags":["github-copilot","oauth","device-flow","schema-validation","response-shape"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}