jackwener/OpenCLI · error · CommandExecutionError
Malformed toutiao recommend row: invalid group_id ${JSON.str
Error message
Malformed toutiao recommend row: invalid group_id ${JSON.stringify(rawGroupId)}. What it means
buildGroupIdentity requires the resolved group id to match /^[A-Za-z0-9_-]+$/. After falling back from explicit group_id to the source_url-derived article id, any id containing other characters (spaces, slashes, CJK, punctuation) fails this check and throws this CommandExecutionError, because the id is used to construct https://www.toutiao.com/group/<id>/.
Source
Thrown at clis/toutiao/utils.js:231
if (error instanceof CommandExecutionError) throw error;
throw new CommandExecutionError(`Malformed toutiao recommend row: invalid source_url ${JSON.stringify(raw)}.`);
}
}
function articleIdFromToutiaoPath(pathname) {
return String(pathname || '').match(/^\/(?:group|article)\/([A-Za-z0-9_-]+)\/?$/)?.[1] || '';
}
function buildGroupIdentity(sourceUrl, rawGroupId) {
const source = firstPartyToutiaoUrl(sourceUrl);
const sourceId = source ? articleIdFromToutiaoPath(source.pathname) : '';
const explicitId = trimOrNull(rawGroupId);
const groupId = explicitId || trimOrNull(sourceId);
if (!groupId) {
throw new CommandExecutionError('Malformed toutiao recommend row: missing group_id and article source_url.');
}
if (!/^[A-Za-z0-9_-]+$/.test(groupId)) {
throw new CommandExecutionError(`Malformed toutiao recommend row: invalid group_id ${JSON.stringify(rawGroupId)}.`);
}
if (sourceId && explicitId && explicitId !== sourceId) {
throw new CommandExecutionError(`Malformed toutiao recommend row: group_id/source_url mismatch for ${JSON.stringify(rawGroupId)}.`);
}
return {
groupId,
url: `https://www.toutiao.com/group/${groupId}/`,
};
}
function formatBehotTime(value) {
const seconds = Number(value);
if (!Number.isFinite(seconds) || seconds <= 0) return null;
return `${new Date(seconds * 1000).toISOString().slice(0, 19)}Z`;
}
/**
* Project a row from the public toutiao channel feed into stable shape.View on GitHub (pinned to 49907e53dc)
Solutions
- Sanitize/decode the id first (decodeURIComponent, trim) and re-check it matches [A-Za-z0-9_-]+ before calling.
- Verify against the current Toutiao id format — if ids changed upstream, update the validation pattern.
- Drop rows with invalid ids and report them; do not attempt to force-strip invalid characters (yields dead links).
- If you construct ids yourself, validate with /^[A-Za-z0-9_-]+$/.test(id) before invoking.
Example fix
// before buildGroupIdentity(url, decodeURIComponent(rawGroupId)); // after const id = decodeURIComponent(rawGroupId).trim(); if (!/^[A-Za-z0-9_-]+$/.test(id)) throw new SkipRowError(id); buildGroupIdentity(url, id);
Defensive patterns
Strategy: validation
Validate before calling
const id = String(rawGroupId || '').trim();
if (!/^[A-Za-z0-9_-]+$/.test(id)) throw new TypeError(`invalid group_id format: ${JSON.stringify(rawGroupId)}`); Type guard
const isValidGroupId = (v) => typeof v === 'string' && /^[A-Za-z0-9_-]+$/.test(v.trim());
Try / catch
try {
const identity = buildGroupIdentity(url, rawGroupId);
} catch (e) {
if (e instanceof CommandExecutionError && e.message.includes('invalid group_id')) return dropRow(rawGroupId);
throw e;
} Prevention
- decodeURIComponent + trim ids extracted from URLs before use.
- Validate against /^[A-Za-z0-9_-]+$/ in your own pipeline first.
- Re-check the pattern if Toutiao changes id formats upstream.
When it happens
Trigger: A group_id containing URL-encoded or raw special characters, whitespace, or full-width characters; a source_url whose captured path segment includes unexpected characters (e.g. '/article/abc.def/').
Common situations: Upstream changing id formats (numeric ids becoming prefixed or composite ids); double-encoded ids like '%7C' left un-decoded; whitespace or trailing '/' fragments captured by an over-broad regex in custom preprocessing.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Malformed toutiao recommend row: off-domain source_url ${JSO
- Malformed toutiao recommend row: invalid source_url ${JSON.s
- Malformed toutiao recommend row: missing group_id and articl
- Malformed toutiao recommend row: group_id/source_url mismatc
- Bilibili creator comparison returned a malformed manuscript
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/e434aaba61406dd9.
Report an issue: GitHub.