jlcodes99/cockpit-tools · error

Zed OAuth start 响应缺少关键字段

Error message

Zed OAuth start 响应缺少关键字段

What it means

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.

Source

Thrown at src/services/zedService.ts:20

import { ZedAccount, ZedOAuthStartResponse, ZedRuntimeStatus } from '../types/zed';

type ZedOAuthStartResponseRaw = Partial<ZedOAuthStartResponse> & {
  login_id?: string;
  verification_uri?: string;
  expires_in?: number;
  interval_seconds?: number;
  callback_url?: string | null;
};

function normalizeZedOAuthStartResponse(raw: ZedOAuthStartResponseRaw): ZedOAuthStartResponse {
  const loginId = raw.loginId ?? raw.login_id ?? '';
  const verificationUri = raw.verificationUri ?? raw.verification_uri ?? '';
  const expiresIn = Number(raw.expiresIn ?? raw.expires_in ?? 0);
  const intervalSeconds = Number(raw.intervalSeconds ?? raw.interval_seconds ?? 0);
  const callbackUrl = raw.callbackUrl ?? raw.callback_url ?? null;

  if (!loginId || !verificationUri) {
    throw new Error('Zed OAuth start 响应缺少关键字段');
  }

  return {
    loginId,
    verificationUri,
    expiresIn: Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn : 600,
    intervalSeconds: Number.isFinite(intervalSeconds) && intervalSeconds > 0 ? intervalSeconds : 1,
    callbackUrl,
  };
}

export async function listZedAccounts(): Promise<ZedAccount[]> {
  return await invoke('list_zed_accounts');
}

export async function deleteZedAccount(accountId: string): Promise<void> {
  return await invoke('delete_zed_account', { accountId });
}

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Log and inspect the raw start response to see what was actually returned
  2. Verify network path: disable proxies/VPNs that could rewrite the response and confirm the official endpoint URL
  3. Update the app to match the current Zed OAuth contract
  4. Retry the login; if persistent, report the raw payload to maintainers

Example fix

// before
const s = await zedOauthLoginStart();
// after
let s;
try { s = await zedOauthLoginStart(); }
catch (e) { console.error('Zed OAuth start invalid:', rawBody); throw e; }
Defensive patterns

Strategy: try-catch

Validate before calling

const raw = await res.clone().json();
if (!(raw?.loginId ?? raw?.login_id) || !(raw?.verificationUri ?? raw?.verification_uri)) {
  console.error('Zed OAuth start body malformed:', raw);
}

Type guard

function hasOAuthStartFields(v: unknown): v is { loginId: string; verificationUri: string } {
  const r = v as any;
  return !!(r?.loginId ?? r?.login_id) && !!(r?.verificationUri ?? r?.verification_uri);
}

Try / catch

try {
  const session = await zedOauthLoginStart();
} catch (e) {
  if (String(e.message).includes('缺少关键字段')) {
    showRetryDialog('Zed login could not start — check network/proxy and retry');
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Zed backend incident, corporate proxy returning a login page or error JSON, or an outdated app calling a renamed endpoint.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/ce67106c2f49b4b8. Report an issue: GitHub.