jackwener/OpenCLI · error · CommandExecutionError
Xiaoyuzhou history returned an invalid ${label}; expected se
Error message
Xiaoyuzhou history returned an invalid ${label}; expected seconds What it means
This CommandExecutionError is thrown by optionalSeconds when a numeric seconds field from the Xiaoyuzhou API (episode.duration, required positive; row.progress, allowed >= 0) is not a safe integer or is below its minimum (duration must be >= 1). The field may legitimately be null, but any present value must be a whole number of seconds.
Source
Thrown at clis/xiaoyuzhou/history.js:42
function requiredId(value, label) {
if (typeof value !== 'string' || !XIAOYUZHOU_ID.test(value)) {
throw new CommandExecutionError(`Xiaoyuzhou history returned an invalid ${label}`);
}
return value.toLowerCase();
}
function requiredString(value, label) {
if (typeof value !== 'string' || !value.trim()) {
throw new CommandExecutionError(`Xiaoyuzhou history returned an invalid ${label}`);
}
return value.trim();
}
function optionalSeconds(value, label, { positive = false } = {}) {
if (value === null) return null;
if (!Number.isSafeInteger(value) || value < (positive ? 1 : 0)) {
throw new CommandExecutionError(`Xiaoyuzhou history returned an invalid ${label}; expected seconds`);
}
return value;
}
function optionalIsoTime(value, label, { required = false } = {}) {
if (value === null) {
if (required) throw new CommandExecutionError(`Xiaoyuzhou history returned a missing ${label}`);
return null;
}
if (typeof value !== 'string' || !value.includes('T') || !Number.isFinite(Date.parse(value))) {
throw new CommandExecutionError(`Xiaoyuzhou history returned an invalid ${label}`);
}
return new Date(value).toISOString();
}
function parseHistoryPage(response) {
if (!isRecord(response) || !isRecord(response.raw) || response.raw.data !== response.data) {
throw new CommandExecutionError('Xiaoyuzhou history returned an unexpected response shape');View on GitHub (pinned to 49907e53dc)
Solutions
- Update the library/CLI to a version matching the current API field types.
- Inspect the raw payload to see the actual type/format of duration or progress (float? string? ISO-8601 duration?).
- If the API now returns milliseconds, convert before parsing (Math.round(ms / 1000)) via a wrapper around requestXiaoyuzhouJson.
- Convert string numerics to Number() in a pre-processing pass if a proxy is responsible.
- Report the changed payload shape to maintainers.
Example fix
// before (API returns ms floats)
{ "episode": { "duration": 3720000.5 } }
// after (normalize before parse)
{ "episode": { "duration": Math.round(raw.duration / 1000) } } // 3720 Defensive patterns
Strategy: type-guard
Validate before calling
function isSeconds(v, { positive = false } = {}) { return v === null || (Number.isSafeInteger(v) && v >= (positive ? 1 : 0)); }
if (!isSeconds(ep.duration, { positive: true }) || !isSeconds(row.progress)) throw new Error('Unexpected seconds field'); Type guard
const isSafeSeconds = (v, min) => typeof v === 'number' && Number.isSafeInteger(v) && v >= min;
Try / catch
try { const rows = await fetchHistory(); } catch (e) { if (e instanceof CommandExecutionError && e.message.includes('expected seconds')) { console.error('duration/progress is not integer seconds — check for ms floats or string values'); } else throw e; } Prevention
- Confirm field units with the current API docs (seconds vs milliseconds).
- Normalize numeric fields (Number(), Math.round) before handing rows to the parser.
- Validate with Number.isSafeInteger, not just typeof number.
- Test against recorded real API payloads, not hand-written mocks.
When it happens
Trigger: parseHistoryEpisode calls optionalSeconds(episode.duration, ..., { positive: true }) and parseProgressRows calls optionalSeconds(row.progress, ...); the error fires when the value is a float (e.g. 12.5), a string like "300", undefined, negative, or exceeds Number.MAX_SAFE_INTEGER — only literal null passes through as null.
Common situations: API version change switching duration from integer seconds to float milliseconds; proxies/mocks returning strings for numeric fields; a new field type (ISO 8601 duration string like PT1H2M3S) replacing raw seconds.
Related errors
- Nowcoder detail returned a mismatched post entity type
- Bilibili ${label} API returned a malformed payload
- Bilibili ${label} API returned malformed data
- Bilibili ${label} API did not return replies
- Bilibili ${label} API returned malformed replies
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c23680b4089cdc3a.
Report an issue: GitHub.