{"record":{"id":"ce67106c2f49b4b8","repo":"jlcodes99/cockpit-tools","slug":"zed-oauth-start","errorCode":null,"errorMessage":"Zed OAuth start 响应缺少关键字段","messagePattern":"Zed OAuth start 响应缺少关键字段","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/zedService.ts","lineNumber":20,"sourceCode":"import { ZedAccount, ZedOAuthStartResponse, ZedRuntimeStatus } from '../types/zed';\n\ntype ZedOAuthStartResponseRaw = Partial<ZedOAuthStartResponse> & {\n  login_id?: string;\n  verification_uri?: string;\n  expires_in?: number;\n  interval_seconds?: number;\n  callback_url?: string | null;\n};\n\nfunction normalizeZedOAuthStartResponse(raw: ZedOAuthStartResponseRaw): ZedOAuthStartResponse {\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('Zed 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 listZedAccounts(): Promise<ZedAccount[]> {\n  return await invoke('list_zed_accounts');\n}\n\nexport async function deleteZedAccount(accountId: string): Promise<void> {\n  return await invoke('delete_zed_account', { accountId });\n}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/services/zedService.ts#L2-L38","documentation":"normalizeZedOAuthStartResponse requires loginId and verificationUri (with snake_case fallbacks) from the Zed OAuth device start response. If either is missing the device flow cannot be linked or polled, so the library throws this error ('Zed OAuth start response missing key fields') from zedOauthLoginStart/zedOauthLoginPeek.","triggerScenarios":"Calling zedOauthLoginStart or zedOauthLoginPeek when the backend returns a body without loginId or verificationUri/verification_uri — error-as-200 payloads, proxy interference, or version drift between client and server field names.","commonSituations":"Zed backend incident, corporate proxy returning a login page or error JSON, or an outdated app calling a renamed endpoint.","solutions":["Log and inspect the raw start response to see what was actually returned","Verify network path: disable proxies/VPNs that could rewrite the response and confirm the official endpoint URL","Update the app to match the current Zed OAuth contract","Retry the login; if persistent, report the raw payload to maintainers"],"exampleFix":"// before\nconst s = await zedOauthLoginStart();\n// after\nlet s;\ntry { s = await zedOauthLoginStart(); }\ncatch (e) { console.error('Zed OAuth start invalid:', rawBody); throw e; }","handlingStrategy":"try-catch","validationCode":"const raw = await res.clone().json();\nif (!(raw?.loginId ?? raw?.login_id) || !(raw?.verificationUri ?? raw?.verification_uri)) {\n  console.error('Zed 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 zedOauthLoginStart();\n} catch (e) {\n  if (String(e.message).includes('缺少关键字段')) {\n    showRetryDialog('Zed login could not start — check network/proxy and retry');\n  } else throw e;\n}","preventionTips":["Confirm the official endpoint URL and TLS chain","Bypass intercepting proxies for OAuth calls","Update the app after backend contract changes","Capture raw response bodies for bug reports"],"tags":["oauth","device-flow","zed","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"}