jlcodes99/cockpit-tools · error

Qoder OAuth start 响应缺少关键字段

Error message

Qoder OAuth start 响应缺少关键字段

What it means

normalizeQoderOAuthStartResponse validates the device-authorization start response from the Qoder backend. loginId and verificationUri are the minimum fields the polling/device-link flow needs; if the raw response (after camelCase/snake_case fallbacks) lacks either, the library cannot start an OAuth device login and throws this Chinese-language error ('OAuth start response missing key fields').

Source

Thrown at src/services/qoderService.ts:28

}

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

function normalizeQoderOAuthStartResponse(raw: QoderOAuthStartResponseRaw): QoderOAuthStartResponse {
  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('Qoder 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 listQoderAccounts(): Promise<QoderAccount[]> {
  return await invoke('list_qoder_accounts');
}

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

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Log the raw response body and confirm whether loginId and verificationUri are present
  2. Check that requests reach the official Qoder endpoint and are not intercepted by a proxy returning an error payload
  3. Update to a backend/client version pair where the OAuth start contract matches (verificationUri vs verification_uri are both handled)
  4. Retry the login start; if it persists, report the backend response shape

Example fix

// before: assuming success
const res = await fetch(startUrl);
const session = normalizeQoderOAuthStartResponse(await res.json());
// after: guard on status and shape first
const res = await fetch(startUrl);
if (!res.ok) throw new Error(`OAuth start failed: ${res.status}`);
const raw = await res.json();
if (!raw?.loginId && !raw?.login_id) throw new Error(`Unexpected OAuth start body: ${JSON.stringify(raw)}`);
const session = normalizeQoderOAuthStartResponse(raw);
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('Qoder 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 qoderOauthLoginStart();
} catch (e) {
  if (String(e.message).includes('缺少关键字段')) {
    showRetryDialog('Qoder login could not start — check network/proxy and retry');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling qoderOauthLoginStart or qoderOauthLoginPeek when the backend returns a 200 body missing loginId or verificationUri/verification_uri — e.g. an error payload shaped as success, a proxy stripping fields, or an API contract change.

Common situations: Server-side outage returning an error JSON with 200 status, corporate proxy/API gateway mangling the response, or running against an outdated backend whose field names changed.

Related errors


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