jackwener/OpenCLI · error · CommandExecutionError

Xiaoyuzhou API rejected the credentials with service code ${

Error message

Xiaoyuzhou API rejected the credentials with service code ${numericCode}

What it means

When the Xiaoyuzhou API envelope returns service code 401 or 403, the CLI raises an authentication error via createXiaoyuzhouAuthError, indicating the stored credentials (token/cookies) were rejected. This distinguishes auth failures from generic service errors so users know to re-authenticate.

Source

Thrown at clis/xiaoyuzhou/auth.js:243

    }
    let parsed;
    try {
        parsed = JSON.parse(bodyText);
    }
    catch (error) {
        throw new CommandExecutionError(`Xiaoyuzhou API returned invalid JSON: ${getErrorMessage(error)}`);
    }
    const serviceCode = parsed?.code;
    if (serviceCode !== undefined && serviceCode !== null) {
        const numericCode = Number(serviceCode);
        if (!Number.isFinite(numericCode)) {
            throw new CommandExecutionError('Xiaoyuzhou API returned an invalid service code');
        }
        if (numericCode === 401 || numericCode === 403) {
            throw createXiaoyuzhouAuthError(`Xiaoyuzhou API rejected the credentials with service code ${numericCode}`);
        }
        if (numericCode !== 0 && numericCode !== 200) {
            throw new CommandExecutionError(
                parsed?.message || parsed?.msg || `Xiaoyuzhou API returned service code ${numericCode}`,
            );
        }
    }
    if (parsed?.success === false) {
        throw new CommandExecutionError(parsed?.message || parsed?.msg || 'Xiaoyuzhou API returned success=false');
    }
    return {
        credentials,
        raw: parsed,
        data: parsed?.data,
    };
}

export async function fetchXiaoyuzhouTranscriptBody(url, fetchImpl = fetch) {
    let response;
    try {
        response = await fetchImpl(url, {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate: run the xiaoyuzhou auth/login flow to obtain fresh credentials, then retry.
  2. Inspect stored credentials (token/cookies file) for truncation or staleness; replace them wholesale.
  3. Verify the Authorization header/cookies are actually attached to the outgoing request.
  4. If 403 persists with valid creds, check for account-level blocks (bans, region restrictions) or IP-based rate limiting.

Example fix

// before: retrying with stale creds
const data = await requestXiaoyuzhouJson(credentials, '/episode/xyz', ...);
// after: catch auth error and re-auth once
try {
  data = await requestXiaoyuzhouJson(credentials, '/episode/xyz', ...);
} catch (e) {
  if (isXiaoyuzhouAuthError(e)) {
    credentials = await refreshXiaoyuzhouCredentials();
    data = await requestXiaoyuzhouJson(credentials, '/episode/xyz', ...);
  } else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before calls: fail fast if credentials are missing/stale
if (!credentials || !credentials.token || (credentials.expiresAt && Date.now() >= credentials.expiresAt)) {
  credentials = await refreshXiaoyuzhouCredentials(); // re-auth before hitting the API
}

Type guard

function isXiaoyuzhouAuthError(e) {
  return e instanceof CommandExecutionError && /rejected the credentials with service code (401|403)/.test(e.message);
}

Try / catch

try {
  return await requestXiaoyuzhouJson(creds, path, params);
} catch (e) {
  if (isXiaoyuzhouAuthError(e)) {
    const fresh = await reauthenticateXiaoyuzhou();
    return await requestXiaoyuzhouJson(fresh, path, params); // retry once with new creds
  }
  throw e;
}

Prevention

When it happens

Trigger: Any requestXiaoyuzhouJson call (result, response, historyResponse, progressResponse, episodeResponse, transcriptResponse) where parsed.code is 401 or 403 — expired auth token, revoked session, missing/invalid Authorization header or cookies, or banned account.

Common situations: Token expired after the session lifetime passed; user logged out elsewhere invalidating the token; copied cookie/auth header incomplete or from a different account; clock skew invalidating signed tokens; account rate-limited into a 403.

Related errors


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