jackwener/OpenCLI · error · CommandExecutionError
xiaohongshu collection landed on unexpected page: ${toCleanS
Error message
xiaohongshu collection landed on unexpected page: ${toCleanString(payload.href) || `${hostname}${pathname}`} What it means
assertOnCollectionProfile verifies the page landed on /user/profile/<userId> for the requested user. Any other location throws CommandExecutionError embedding the actual href (or hostname+pathname). This catches wrong navigations and unexpected redirects so scraping never reads another page's data.
Source
Thrown at clis/xiaohongshu/collection-helpers.js:199
if (payload === true) {
throw new AuthRequiredError('www.xiaohongshu.com', 'Xiaohongshu collection page requires login; re-login to xiaohongshu.com and retry.');
}
}
export async function assertOnCollectionProfile(page, userId) {
await throwIfLoginWall(page);
const payload = unwrapBrowserResult(await page.evaluate(CURRENT_LOCATION_JS));
if (!isObject(payload)) {
throw new CommandExecutionError('xiaohongshu collection page returned malformed location');
}
const hostname = toCleanString(payload.hostname).toLowerCase();
const pathname = toCleanString(payload.pathname);
if (hostname === 'www.xiaohongshu.com' && pathname === '/login') {
throw new AuthRequiredError('xiaohongshu collection page requires login');
}
const expectedPath = `/user/profile/${toCleanString(userId)}`;
if (hostname !== 'www.xiaohongshu.com' || pathname !== expectedPath) {
throw new CommandExecutionError(`xiaohongshu collection landed on unexpected page: ${toCleanString(payload.href) || `${hostname}${pathname}`}`);
}
}
async function accumulateInterceptedNotes(page, bucket, fallbackUserId) {
const reqs = await page.getInterceptedRequests();
if (!Array.isArray(reqs)) {
throw new CommandExecutionError('xiaohongshu collection interceptor returned malformed captures');
}
if (Array.isArray(reqs) && reqs.length > 0)
bucket.push(...reqs);
return extractNotesFromResponses(bucket, fallbackUserId);
}
export async function resolveXhsUserId(page, rawId) {
if (rawId)
return normalizeXhsUserId(String(rawId));
await page.goto('https://www.xiaohongshu.com/explore');
await page.wait(2);View on GitHub (pinned to 49907e53dc)
Solutions
- Print the actual href from the error message and compare with the expected /user/profile/<userId> path
- Verify the userId is the correct xiaohongshu profile identifier (from the profile URL, not the numeric uid)
- Handle any risk-control/verification page before scraping
- Fix your navigation URL construction to use the exact profile URL format
Example fix
// before
await page.goto(`https://www.xiaohongshu.com/user/profile/${uid}`); // uid = numeric DB id
// after
const profileId = user.xhsProfileId; // id as it appears in the profile URL
await page.goto(`https://www.xiaohongshu.com/user/profile/${profileId}`); Defensive patterns
Strategy: validation
Validate before calling
const expected = `https://www.xiaohongshu.com/user/profile/${userId}`;
if (page.url() !== expected) await page.goto(expected, { waitUntil: 'networkidle' }); Type guard
const onExpectedProfile = (url, userId) => { try { const u = new URL(url); return u.hostname === 'www.xiaohongshu.com' && u.pathname === `/user/profile/${userId}`; } catch { return false; } }; Try / catch
try { notes = await fetchXhsCollectionNotes(page, userId); } catch (e) { const m = String(e.message).match(/unexpected page: (\S+)/); if (m) { console.error('landed on', m[1]); await page.goto(expectedUrl, { waitUntil: 'networkidle' }); notes = await fetchXhsCollectionNotes(page, userId); } else throw e; } Prevention
- Use the exact profile id from the profile URL, not internal numeric uids
- Log and compare actual vs expected URL whenever navigation is involved
- Handle risk-control/verification interstitials before scraping
- Build navigation URLs from a single tested helper
When it happens
Trigger: Navigation landed on the home feed, a verification page, a note detail page, or another user's profile — any hostname/path other than www.xiaohongshu.com + /user/profile/<userId>.
Common situations: Wrong userId passed in (typo or numeric id vs profile id); xiaohongshu redirecting to a risk-control/verify page; URL-building bug concatenating a bad path; locale prefix paths (e.g. /en/user/...) failing the exact match.
Related errors
- ChatGPT did not open the requested project ${id}. Current UR
- Title page did not finish loading: ${id}
- LinkedIn company extraction ended outside a company page
- SPA navigation to Twitter followers failed
- UISDC news page returned an unreadable payload
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/17178eab30912296.
Report an issue: GitHub.