{"record":{"id":"17b69fb400b53af3","repo":"jlcodes99/cockpit-tools","slug":"trae-oauth-start","errorCode":null,"errorMessage":"Trae OAuth start 响应缺少关键字段","messagePattern":"Trae OAuth start 响应缺少关键字段","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/traeService.ts","lineNumber":31,"sourceCode":"}\n\ntype TraeOAuthStartResponseRaw = Partial<TraeOAuthStartResponse> & {\n  login_id?: string;\n  verification_uri?: string;\n  expires_in?: number;\n  interval_seconds?: number;\n  callback_url?: string | null;\n};\n\nfunction normalizeTraeOAuthStartResponse(raw: TraeOAuthStartResponseRaw): TraeOAuthStartResponse {\n  const loginId = raw.loginId ?? raw.login_id ?? '';\n  const verificationUri = raw.verificationUri ?? raw.verification_uri ?? '';\n  const expiresIn = Number(raw.expiresIn ?? raw.expires_in ?? 0);\n  const intervalSeconds = Number(raw.intervalSeconds ?? raw.interval_seconds ?? 0);\n  const callbackUrl = raw.callbackUrl ?? raw.callback_url ?? null;\n\n  if (!loginId || !verificationUri) {\n    throw new Error('Trae OAuth start 响应缺少关键字段');\n  }\n\n  return {\n    loginId,\n    verificationUri,\n    expiresIn: Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn : 600,\n    intervalSeconds: Number.isFinite(intervalSeconds) && intervalSeconds > 0 ? intervalSeconds : 1,\n    callbackUrl,\n  };\n}\n\nexport async function listTraeAccounts(): Promise<TraeAccount[]> {\n  return await invoke('list_trae_accounts');\n}\n\nexport async function deleteTraeAccount(accountId: string): Promise<void> {\n  return await invoke('delete_trae_account', { accountId });\n}","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/services/traeService.ts#L13-L49","documentation":"normalizeTraeOAuthStartResponse validates the Trae device-authorization start response. The device-link flow cannot proceed without loginId and verificationUri (camelCase or snake_case); if both lookups yield empty values the library throws this error ('Trae OAuth start response missing key fields') rather than returning a half-usable session.","triggerScenarios":"Calling traeOauthLoginStart when the backend response omits loginId or verificationUri/verification_uri — an error body returned with HTTP 200, a gateway/proxy altering the payload, or an API schema change between client and server versions.","commonSituations":"Trae service outage returning error JSON, misconfigured base URL pointing at a wrong endpoint, or stale app version after a backend field rename.","solutions":["Inspect the raw HTTP response body for loginId and verificationUri","Confirm the request hits the correct Trae OAuth endpoint (check base URL/proxy config)","Update the app so client and backend OAuth contracts match (both naming styles are handled)","Retry the start call; if reproducible, capture the payload and report it"],"exampleFix":"// before\nconst session = await traeOauthLoginStart();\n// after\ntry {\n  const session = await traeOauthLoginStart();\n} catch (e) {\n  console.error('Trae OAuth start failed:', e.message, rawBody);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const raw = await res.clone().json();\nif (!(raw?.loginId ?? raw?.login_id) || !(raw?.verificationUri ?? raw?.verification_uri)) {\n  console.error('Trae OAuth start body malformed:', raw);\n}","typeGuard":"function hasOAuthStartFields(v: unknown): v is { loginId: string; verificationUri: string } {\n  const r = v as any;\n  return !!(r?.loginId ?? r?.login_id) && !!(r?.verificationUri ?? r?.verification_uri);\n}","tryCatchPattern":"try {\n  const session = await traeOauthLoginStart();\n} catch (e) {\n  if (String(e.message).includes('缺少关键字段')) {\n    showRetryDialog('Trae login could not start — verify endpoint/proxy and retry');\n  } else throw e;\n}","preventionTips":["Check HTTP status before parsing responses","Exclude provider OAuth endpoints from proxy rewriting","Keep client and backend versions in sync","Log raw payloads on failure"],"tags":["oauth","device-flow","trae","api-response"],"backgroundTag":"oauth-start-response-invalid","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}