jackwener/OpenCLI · error · CommandExecutionError
Xiaoyuzhou history returned an invalid loadMoreKey
Error message
Xiaoyuzhou history returned an invalid loadMoreKey
What it means
When a pagination cursor (loadMoreKey) is present, it must be a non-empty string; the library trims it and passes it back as the next request body. A cursor that is a number, object, null-like, or whitespace-only string cannot be safely forwarded, so CommandExecutionError is thrown instead of issuing a malformed continuation request.
Source
Thrown at clis/xiaoyuzhou/history.js:79
}
const payload = response?.data;
let entries;
let next;
if (Array.isArray(payload)) {
entries = payload;
next = response.raw?.loadMoreKey;
}
else if (isRecord(payload) && Array.isArray(payload.data)
&& !Object.prototype.hasOwnProperty.call(response.raw, 'loadMoreKey')) {
entries = payload.data;
next = payload.loadMoreKey;
}
else {
throw new CommandExecutionError('Xiaoyuzhou history returned an unexpected response shape');
}
if (next == null || next === '') return { entries, next: null };
if (typeof next !== 'string' || !next.trim()) {
throw new CommandExecutionError('Xiaoyuzhou history returned an invalid loadMoreKey');
}
if (entries.length === 0) {
throw new CommandExecutionError('Xiaoyuzhou history returned an empty page with a continuation cursor');
}
return { entries, next: next.trim() };
}
function parseHistoryEpisode(entry, rowNumber) {
if (!isRecord(entry) || !isRecord(entry.episode)) {
throw new CommandExecutionError(`Xiaoyuzhou history row ${rowNumber} is malformed; expected episode metadata`);
}
const episode = entry.episode;
if (!isRecord(episode.podcast) || typeof episode.isFinished !== 'boolean') {
throw new CommandExecutionError(`Xiaoyuzhou history row ${rowNumber} is missing podcast or finished state`);
}
return {
eid: requiredId(episode.eid, `eid in row ${rowNumber}`),
pid: requiredId(episode.pid, `pid in row ${rowNumber}`),View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw loadMoreKey value from the failing page to see its actual type/content.
- Retry the command — a transiently truncated response can produce an empty cursor string.
- Update the CLI/library if the API switched to a non-string cursor format.
- Fetch with a smaller --limit (or without --all) to reduce pages traversed, sidestepping the bad cursor.
- Report/patch parseHistoryPage to normalize the new cursor format.
Example fix
// before
{ "loadMoreKey": { "offset": 20 } }
// after (expected string cursor)
{ "loadMoreKey": "eyJvZmZzZXQiOjIwfQ==" } Defensive patterns
Strategy: validation
Validate before calling
function isValidCursor(k) { return k == null || k === '' || (typeof k === 'string' && k.trim().length > 0); }
// verify before paginating: every page.next satisfies isValidCursor Type guard
function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; } Try / catch
try {
const rows = await runHistory();
} catch (e) {
if (e.message === 'Xiaoyuzhou history returned an invalid loadMoreKey') {
// stop pagination and return rows collected so far
} else throw e;
} Prevention
- Retry on transient truncation; cursors corrupted in transit usually succeed on retry
- Avoid response-rewriting proxies between the CLI and api.xiaoyuzhoufm.com
- Update the CLI when the API migrates to non-string cursor tokens
When it happens
Trigger: The history API returns loadMoreKey as a non-string (number, nested object) or an all-whitespace string while more pages remain, during `xiaoyuzhou history` or `--all` pagination.
Common situations: API version change alters cursor encoding (e.g. opaque object cursor instead of string token); a transparent proxy truncates the cursor; a mock fixture uses a placeholder cursor value.
Related errors
- juejin recommend returned a malformed cursor
- juejin recommend returned has_more without a next cursor
- Xiaoyuzhou history returned an empty page with a continuatio
- Xiaoyuzhou playback progress returned unrequested eid ${eid}
- Instagram following returned malformed users payload
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/742ce0c3c18b61aa.
Report an issue: GitHub.