jackwener/OpenCLI · error · CommandExecutionError
Malformed toutiao recommend row: missing group_id and articl
Error message
Malformed toutiao recommend row: missing group_id and article source_url.
What it means
buildGroupIdentity derives a group id for a recommend row from either an explicit group_id or the article id embedded in the source_url path (/group/<id>/ or /article/<id>/). When both are absent (or the URL itself was unusable), no identity can be built, so it throws this CommandExecutionError — the row cannot be deduplicated or linked.
Source
Thrown at clis/toutiao/utils.js:228
}
return url;
} catch (error) {
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`;
}View on GitHub (pinned to 49907e53dc)
Solutions
- Ensure each row carries either a group_id or a toutiao.com /group/<id>/ or /article/<id>/ source_url.
- Skip rows lacking both identifiers and log them instead of failing the whole run.
- If the URL is a non-article toutiao page, extract the id with your own path rule before calling.
- Check for upstream API changes — a renamed field (e.g. group_id -> item_id) needs a mapping update.
Example fix
// before const identity = buildGroupIdentity(row.source_url, row.group_id); // after if (!row.group_id && !/\/group|article\/\w+/.test(row.source_url || '')) return skip(row); const identity = buildGroupIdentity(row.source_url, row.group_id);
Defensive patterns
Strategy: validation
Validate before calling
function hasGroupIdentity(row) {
const m = String(row.source_url || '').match(/^\/(?:group|article)\/([A-Za-z0-9_-]+)\/?$/) || String(row.source_url || '').replace(/^https:\/\/[^/]+/, '').match(/^\/(?:group|article)\/([A-Za-z0-9_-]+)\/?$/);
return Boolean(String(row.group_id || '').trim() || (m && m[1]));
}
if (!hasGroupIdentity(row)) skipRow(row); Type guard
const hasIdentity = (row) => !!(String(row?.group_id || '').trim() || /\/(?:group|article)\/[A-Za-z0-9_-]+\/?$/.test(String(row?.source_url || '').replace(/^https?:\/\/[^/]+/, '')));
Try / catch
try {
const identity = buildGroupIdentity(row.source_url, row.group_id);
} catch (e) {
if (e instanceof CommandExecutionError && e.message.includes('missing group_id')) return skipRow(row);
throw e;
} Prevention
- Require either group_id or an article/group source_url at the schema level of your ingestion.
- Skip non-article rows (videos, topics, homepages) before identity building.
- Watch for upstream field renames (group_id -> item_id) and map them.
When it happens
Trigger: A recommend row with no group_id field AND a source_url that is null, empty, off-domain, or a toutiao.com URL whose pathname is not /group/<id>/ or /article/<id>/ (e.g. a homepage or topic URL).
Common situations: Feed rows for non-article content (videos, user pages, special topics) lacking ids; scraping a page where group_id was renamed or moved; fixtures missing the id fields entirely.
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
- nuget package registration page ${pageIndex + 1} is missing
- Malformed toutiao recommend row: off-domain source_url ${JSO
- Malformed toutiao recommend row: invalid source_url ${JSON.s
- Malformed toutiao recommend row: invalid group_id ${JSON.str
- Malformed toutiao recommend row: group_id/source_url mismatc
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5b420fbaa78958c6.
Report an issue: GitHub.