jackwener/OpenCLI · error · CliError
AUTH_REQUIRED
AUTH_REQUIRED
Error message
AUTH_REQUIRED: Not logged in to WeRead
What it means
Thrown by fetchPrivateApi when the private WeRead API indicates the session is not authenticated: either an HTTP 401 status or a JSON body whose errcode is in {-2010, -2012} (WeRead's auth error codes), detected by isAuthErrorResponse. Thrown as CliError code AUTH_REQUIRED with the remediation hint to log in to weread.qq.com in Chrome first, because cookies for the request are extracted from the browser profile.
Source
Thrown at clis/weread/utils.js:171
'User-Agent': WEREAD_UA,
'Origin': 'https://weread.qq.com',
'Referer': 'https://weread.qq.com/',
...(cookieHeader ? { 'Cookie': cookieHeader } : {}),
},
});
}
catch (error) {
throw new CliError('FETCH_ERROR', `Failed to fetch ${path}: ${error instanceof Error ? error.message : String(error)}`, 'WeRead API may be temporarily unavailable');
}
let data;
try {
data = await resp.json();
}
catch {
throw new CliError('PARSE_ERROR', `Invalid JSON response for ${path}`, 'WeRead may have returned an HTML error page');
}
if (isAuthErrorResponse(resp, data)) {
throw new CliError('AUTH_REQUIRED', 'Not logged in to WeRead', 'Please log in to weread.qq.com in Chrome first');
}
if (!resp.ok) {
throw new CliError('FETCH_ERROR', `HTTP ${resp.status} for ${path}`, 'WeRead API may be temporarily unavailable');
}
if (data?.errcode != null && data.errcode !== 0) {
throw new CliError('API_ERROR', data.errmsg ?? `WeRead API error ${data.errcode}`);
}
return data;
}
function getUniqueRawBookIds(snapshot) {
return Array.from(new Set(snapshot.rawBooks
.map((book) => String(book?.bookId || '').trim())
.filter(Boolean)));
}
/** Mirror of hasTrustedIndexes in buildShelfSnapshotPollScript — keep in sync */
function getTrustedIndexedBookIds(snapshot) {
const rawBookIds = getUniqueRawBookIds(snapshot);
if (rawBookIds.length === 0)View on GitHub (pinned to 49907e53dc)
Solutions
- Open https://weread.qq.com in Chrome, log in (scan QR with the WeChat/WeRead app), then rerun the CLI — this refreshes the extracted cookies.
- Verify the cookies being sent: check that wr_vid and wr_sso exist via page.getCookies({ domain: 'weread.qq.com' }).
- Confirm the CLI is pointed at the Chrome profile you actually logged in with (not a work/personal profile switch).
- Catch CliError code 'AUTH_REQUIRED' in scripts and pause/notify the user instead of retrying — retrying cannot fix an expired session.
- If sessions expire frequently, keep the Chrome tab logged in / disable 'clear cookies on exit' settings.
Example fix
// before
const highlights = await fetchPrivateApi(page, '/u/book/notes', params);
// after
try {
const highlights = await fetchPrivateApi(page, '/u/book/notes', params);
} catch (e) {
if (e.code === 'AUTH_REQUIRED') {
console.error('Please log in to https://weread.qq.com in Chrome, then retry.');
process.exitCode = 2;
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check auth cookies exist in the browser profile before private-API calls
const cookies = await page.getCookies({ domain: 'weread.qq.com' });
const loggedIn = ['wr_vid', 'wr_sso'].every(n => cookies.some(c => c.name === n));
if (!loggedIn) console.warn('Not logged in to WeRead — AUTH_REQUIRED expected; log in at https://weread.qq.com in Chrome'); Type guard
function isAuthRequiredError(e) {
return e != null && typeof e === 'object' && e.code === 'AUTH_REQUIRED';
} Try / catch
import { CliError } from '@jackwener/opencli/errors';
try {
const data = await callWereadPrivateCommand();
} catch (e) {
if (isAuthRequiredError(e)) {
console.error('Not logged in to WeRead. Log in to https://weread.qq.com in Chrome, then rerun.');
process.exitCode = 2; // do NOT retry — the session cannot self-heal
return;
}
throw e;
} Prevention
- Verify wr_vid and wr_sso cookies exist before invoking private-API commands
- Log in freshly in Chrome whenever AUTH_REQUIRED appears; never retry blindly
- Ensure the CLI reads cookies from the Chrome profile you actually log in with
- Disable cookie-clearing on browser exit for weread.qq.com to reduce session loss
- In scripts, exit with a distinct code on AUTH_REQUIRED so pipelines can prompt the user
When it happens
Trigger: Any fetchPrivateApi call where resp.status === 401 or Number(data.errcode) is -2010/-2012: expired wr_sso/wr_vid session cookies, a Chrome profile that was never logged in, cookies cleared by browser hygiene settings, or the user logging out in Chrome since the last run.
Common situations: WeRead session expiry (days after last browser login); switching Chrome profiles so the CLI reads cookies from a non-logged-in profile; clearing cookies/site data; cookie extraction from the wrong profile directory; using the CLI before ever logging in on that machine.
Related errors
- bilibili.com
- WeRead wr_vid cookie missing
- ${result.detail}
- Waiting for Bilibili session cookies
- Bilibili ${label} API requires login or permission: ${messag
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8c49fe8565e6f575.
Report an issue: GitHub.