jackwener/OpenCLI · error · CliError

AUTH_REQUIRED

AUTH_REQUIRED

Error message

Xiaoyuzhou refresh token is missing

What it means

createXiaoyuzhouAuthError thrown from refreshXiaoyuzhouCredentials when the stored credentials have no refresh_token. Without it the library cannot call the /app_auth_tokens.refresh endpoint to obtain a new access token, so any authenticated request fails with AUTH_REQUIRED.

Source

Thrown at clis/xiaoyuzhou/auth.js:129

        'x-jike-device-id': credentials.device_id || XIAOYUZHOU_DEFAULT_DEVICE_ID,
        'x-jike-device-properties': credentials.device_properties ?? XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES,
    };
    if (credentials.access_token) {
        headers['x-jike-access-token'] = credentials.access_token;
    }
    if (includeRefreshToken && credentials.refresh_token) {
        headers['x-jike-refresh-token'] = credentials.refresh_token;
    }
    if (includeLocalTime) {
        headers['Local-Time'] = new Date().toISOString();
        headers.Timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
    }
    return headers;
}

export async function refreshXiaoyuzhouCredentials(credentials, fetchImpl = fetch) {
    if (!credentials.refresh_token) {
        throw createXiaoyuzhouAuthError('Xiaoyuzhou refresh token is missing');
    }
    let response;
    try {
        response = await fetchImpl(`${XIAOYUZHOU_API_BASE_URL}/app_auth_tokens.refresh`, {
            method: 'POST',
            headers: buildXiaoyuzhouHeaders(credentials, {
                contentType: 'application/x-www-form-urlencoded; charset=utf-8',
                includeLocalTime: true,
                includeRefreshToken: true,
            }),
            signal: AbortSignal.timeout(20_000),
        });
    }
    catch (error) {
        throw new CommandExecutionError(`Failed to refresh Xiaoyuzhou credentials: ${getErrorMessage(error)}`);
    }
    const bodyText = await response.text();
    if (!response.ok) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the Xiaoyuzhou login/auth flow to obtain a fresh access_token + refresh_token pair and persist both
  2. Inspect stored credentials and ensure refresh_token is present and non-empty
  3. Guard the refresh path: if refresh_token is missing, fail fast into re-login instead of calling the refresh endpoint
  4. Check that the field name is correct (refresh_token) wherever credentials are serialized

Example fix

// before: refreshing with empty token
await refreshXiaoyuzhouCredentials({ access_token: 'x', refresh_token: '' });
// after: re-login first, then refresh
if (!credentials.refresh_token) {
  credentials = await xiaoyuzhouLogin(); // persists both tokens
}
await refreshXiaoyuzhouCredentials(credentials);
Defensive patterns

Strategy: validation

Validate before calling

if (!credentials || typeof credentials.refresh_token !== 'string' || !credentials.refresh_token) {
  throw new Error('Xiaoyuzhou refresh token missing — re-run login before making API calls');
}

Type guard

function hasRefreshToken(c) { return typeof c === 'object' && c !== null && typeof c.refresh_token === 'string' && c.refresh_token.length > 0; }

Try / catch

try {
  const data = await requestXiaoyuzhouJson(url, credentials);
} catch (e) {
  if (e.code === 'AUTH_REQUIRED' && /refresh token is missing/.test(e.message)) {
    credentials = await xiaoyuzhouLogin(); // obtain a fresh token pair
    return await requestXiaoyuzhouJson(url, credentials);
  }
  throw e;
}

Prevention

When it happens

Trigger: requestXiaoyuzhouJson detects an expired access token and calls refreshed → refreshXiaoyuzhouCredentials, but credentials.refresh_token is empty/undefined (never captured at login, or wiped by a prior bad refresh).

Common situations: Login flow stored only the access token; a previous refresh wrote empty tokens (normalizeXiaoyuzhouCredentials persisted '' for refresh_token); config/env var holding credentials was truncated or never set.

Related errors


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