jackwener/OpenCLI · error · AuthRequiredError

zsxq /v2/users/self 200 but user_id missing — incomplete ses

Error message

zsxq /v2/users/self 200 but user_id missing — incomplete session

What it means

The probe got HTTP 200 from /v2/users/self (so the session is authenticated enough to pass), but the response body contained no resolvable user_id (u.user_id and u.id both empty). verifyZsxqIdentity throws AuthRequiredError('zsxq.com', '... incomplete session') because a valid identity could not be established.

Source

Thrown at clis/zsxq/auth.js:41

        }
        if (!r.ok) return { kind: 'http', httpStatus: r.status };
        const d = await r.json();
        if (d?.succeeded === false || !d?.resp_data?.user) {
          return { kind: 'auth', detail: 'zsxq /v2/users/self returned succeeded=false — anonymous' };
        }
        const u = d.resp_data.user;
        return { ok: true, user_id: String(u.user_id || u.id || ''), name: String(u.name || u.nickname || '') };
      } catch (e) {
        return { kind: 'exception', detail: String(e && e.message || e) };
      }
    })()
  `);
  if (probe?.kind === 'auth') throw new AuthRequiredError('zsxq.com', probe.detail);
  if (probe?.kind === 'http') throw new CommandExecutionError(`HTTP ${probe.httpStatus} from zsxq /v2/users/self`);
  if (probe?.kind === 'exception') throw new CommandExecutionError(`zsxq whoami failed: ${probe.detail}`);
  if (!probe?.ok) throw new CommandExecutionError(`Unexpected zsxq probe: ${JSON.stringify(probe)}`);
  if (!probe.user_id) {
    throw new AuthRequiredError('zsxq.com', 'zsxq /v2/users/self 200 but user_id missing — incomplete session');
  }
  return { user_id: probe.user_id, name: probe.name };
}

registerSiteAuthCommands({
  site: 'zsxq',
  domain: 'zsxq.com',
  loginUrl: 'https://wx.zsxq.com/login',
  columns: ['user_id', 'name'],
  verify: verifyZsxqIdentity,
  // No-navigation poll: probe the API from the current page so the login-page
  // QR code isn't reset by a goto on every interval.
  poll: async (page) => {
    const loggedIn = await page.evaluate(`(async () => {
      try {
        const r = await fetch('https://api.zsxq.com/v2/users/self', { credentials: 'include', headers: { Accept: 'application/json' } });
        if (!r.ok) return false;
        const d = await r.json();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log out and log back in to zsxq in the browser profile to rebuild a complete session, then retry.
  2. Log the raw probe response body to check whether the field names changed (user_id/id, name/nickname) and update the extraction if the API schema shifted.
  3. Confirm the account is fully active (not suspended/restricted) by visiting zsxq.com in the same profile.
  4. Update the library in case a newer version already handles the changed response schema.

Example fix

// before
const u = await r.json();
const userId = String(u.user_id || u.id || '');
// after
const d = await r.json();
const u = d?.resp_data ?? d;
const userId = String(u?.user_id || u?.id || '');
if (!userId) throw new AuthRequiredError('zsxq.com', 'no user identity in response');
Defensive patterns

Strategy: validation

Validate before calling

const r = await page.request.get('https://api.zsxq.com/v2/users/self');
const d = await r.json();
const u = d?.resp_data ?? d;
if (!String(u?.user_id || u?.id || '')) throw new Error('session has no user_id — re-login required');

Type guard

const hasUserId = (d) => Boolean(String(d?.resp_data?.user_id || d?.resp_data?.id || d?.user_id || d?.id || ''));

Try / catch

try {
  return await verifyZsxqIdentity(page);
} catch (e) {
  if ((e.message || '').includes('incomplete session')) {
    await logoutAndLoginZsxq(page);
    return verifyZsxqIdentity(page);
  }
  throw e;
}

Prevention

When it happens

Trigger: zsxq /v2/users/self returns 200 but with an unexpected/partial body: e.g. resp_data missing, fields renamed by an API change, or a session valid for cookies but not for full account data (partially invalidated login).

Common situations: zsxq API schema change breaking the user_id/nickname extraction;半 logged-in states after password change; server returning an empty resp_data for restricted accounts.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/a03ebbee9e0330d1. Report an issue: GitHub.