jackwener/OpenCLI · error · CommandExecutionError
${webHost} feed: feed item ${id} is missing xsecToken; canno
Error message
${webHost} feed: feed item ${id} is missing xsecToken; cannot build a signed drill-down URL What it means
Feed items also require an xsecToken; runFeed throws this error when toCleanString(row.xsecToken) is empty, because signed drill-down URLs for note detail cannot be constructed without it.
Source
Thrown at clis/xiaohongshu/feed.js:126
throw new CommandExecutionError(`${webHost} feed: ${data.error}`, `The SPA may still be hydrating; reload ${webHost}/explore and retry.`);
}
if (!Array.isArray(data.items)) {
throw new CommandExecutionError(`${webHost} feed: unexpected items payload shape`);
}
const rows = [];
for (const row of data.items) {
if (rows.length >= limit)
break;
if (!row || typeof row !== 'object') {
throw new CommandExecutionError(`${webHost} feed: malformed feed item`);
}
const id = toCleanString(row.id);
if (!id) {
throw new CommandExecutionError(`${webHost} feed: feed item is missing note id`);
}
const xsecToken = toCleanString(row.xsecToken);
if (!xsecToken) {
throw new CommandExecutionError(`${webHost} feed: feed item ${id} is missing xsecToken; cannot build a signed drill-down URL`);
}
rows.push({
id,
title: toCleanString(row.title),
type: toCleanString(row.type),
author: toCleanString(row.author),
likes: toCleanString(row.likes),
url: buildFeedNoteUrl(webHost, id, xsecToken),
});
}
if (rows.length === 0) {
throw new EmptyResultError(`${webHost}/feed`, 'No feed items in the hydrated store.');
}
return rows;
}
export const command = cli({
site: 'xiaohongshu',View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the row in DevTools to find the current token field name and update FEEDS_READ_JS/mapping (e.g. row.xsec_token)
- Retry after full hydration so tokens are populated
- Skip token-less items and build URLs only for complete rows
- Re-fetch the feed via the same explore entry point that includes xsecToken
Example fix
// before const xsecToken = toCleanString(row.xsecToken); // after (tolerate alternate key) const xsecToken = toCleanString(row.xsecToken ?? row.xsec_token);
Defensive patterns
Strategy: validation
Validate before calling
const drillable = (data.items ?? []).filter(r => r && toCleanString(r.xsecToken ?? r.xsec_token) && toCleanString(r.id));
Type guard
function hasXsecToken(row) { return !!row && typeof row === 'object' && Boolean(toCleanString(row.xsecToken ?? row.xsec_token)); } Try / catch
try {
const rows = await runFeed(page, webHost, limit);
} catch (err) {
if (err instanceof CommandExecutionError && err.message.includes('xsecToken')) {
// skip token-less items or re-fetch feed from the entry point that issues tokens
} else throw err;
} Prevention
- Map both xsecToken and xsec_token keys in the parser
- Re-fetch the feed when tokens are missing; tokens come with the explore payload
- Wait for full hydration before reading items
- Skip promoted/placeholder cards that lack tokens
When it happens
Trigger: A row has a valid id but no xsecToken field (empty/undefined), commonly when the feed payload variant differs (e.g. different entry point or a site change moving the token).
Common situations: Site changes renaming xsecToken (e.g. xsec_token), feeds fetched from a context that doesn't issue tokens, promoted cards lacking tokens, partial hydration dropping the token field.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- ${webHost} feed: unexpected items payload shape
- ${webHost} feed: malformed feed item
- ${webHost} feed: feed item is missing note id
- 12306 ${endpoint} returned an unexpected payload shape
- Failed to parse 12306 station_name.js: no station records fo
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/bcdf41e94a6352af.
Report an issue: GitHub.