jackwener/OpenCLI · error · CommandExecutionError
Nowcoder detail returned a mismatched post entity type
Error message
Nowcoder detail returned a mismatched post entity type
What it means
projectNowcoderDetail checks that data.entityType matches the type expected from the parsed target: the content entity type for /discuss/<id> targets, or the moment type for /feed/main/detail/<uuid> targets. If the API returns an entity of a different type (e.g. you passed a discuss ID but the API resolved to a different entity kind), this CommandExecutionError is thrown to prevent projecting data under the wrong shape.
Source
Thrown at clis/nowcoder/posts.js:205
throw new ArgumentError('nowcoder detail requires a numeric content ID, moment UUID, or canonical Nowcoder URL');
}
const host = url.hostname.toLowerCase();
if (url.protocol !== 'https:' || url.username || url.password || url.port || url.hash
|| (host !== 'nowcoder.com' && host !== 'www.nowcoder.com')) {
throw new ArgumentError('nowcoder detail only accepts canonical https://www.nowcoder.com post URLs');
}
const content = url.pathname.match(/^\/discuss\/([1-9]\d*)\/?$/);
if (content) return { post_type: 'content', value: content[1] };
const moment = url.pathname.match(/^\/feed\/main\/detail\/([0-9a-f]{32})\/?$/i);
if (moment) return { post_type: 'moment', value: moment[1].toLowerCase() };
throw new ArgumentError('Unsupported Nowcoder URL; expected /discuss/<content-id> or /feed/main/detail/<moment-uuid>');
}
export function projectNowcoderDetail(data, target) {
if (!isRecord(data) || !isRecord(data.frequencyData)) throw new CommandExecutionError('Nowcoder detail returned malformed post data');
const isContent = target.post_type === 'content';
const expectedEntityType = isContent ? CONTENT_ENTITY_TYPE : MOMENT_TYPE;
if (data.entityType !== expectedEntityType) throw new CommandExecutionError('Nowcoder detail returned a mismatched post entity type');
const uuid = requiredUuid(data.uuid, `${target.post_type} uuid`);
const entityId = requiredId(data.entityId, `${target.post_type} entity id`);
const id = isContent ? requiredId(data.id, 'content id') : uuid;
if (isContent ? id !== target.value : uuid !== target.value) throw new CommandExecutionError('Nowcoder detail returned a different post identity');
if (!isContent && entityId !== requiredId(data.id, 'moment id')) throw new CommandExecutionError('Nowcoder detail returned mismatched moment entity ids');
const expectedAuthorId = isContent ? data.authorId : data.userId;
const body = cleanBody(isContent ? data.richText : data.content, `${target.post_type} detail body`);
return {
post_type: target.post_type,
id,
uuid,
entity_id: entityId,
url: isContent
? `https://www.nowcoder.com/discuss/${id}`
: `https://www.nowcoder.com/feed/main/detail/${uuid}`,
title: optionalText(data.title, `${target.post_type} title`) || '(untitled)',
...authorFields(data.userBrief, expectedAuthorId, target.post_type),
content: body,View on GitHub (pinned to 49907e53dc)
Solutions
- Confirm the URL/ID is really a discuss post (www.nowcoder.com/discuss/<id>) or a feed moment (/feed/main/detail/<uuid>) and not another entity type.
- Fetch the target directly by its canonical ID/UUID rather than a URL of the wrong kind.
- If the API legitimately changed entityType values, update the CONTENT_ENTITY_TYPE / MOMENT_TYPE constants in the library.
Example fix
// before nowcoder detail "https://www.nowcoder.com/feed/main/detail/abc123" // uuid passed via wrong route/shape // after nowcoder detail "https://www.nowcoder.com/discuss/70123456" // content post via content route
Defensive patterns
Strategy: validation
Validate before calling
// before calling, ensure the target kind matches the route kind
function targetKindMatches(value) {
if (/^\/discuss\/\d+/.test(value)) return 'content';
if (/^\/feed\/main\/detail\/[0-9a-f]{32}$/i.test(value)) return 'moment';
return /^[0-9a-f]{32}$/i.test(value) ? 'moment' : 'content';
} Type guard
function isMomentTarget(target) {
return target !== null && typeof target === 'object' && target.post_type === 'moment'
&& typeof target.value === 'string' && /^[0-9a-f]{32}$/.test(target.value);
} Try / catch
try {
const post = await nowcoderDetail(target);
} catch (err) {
if (err instanceof CommandExecutionError && /mismatched post entity type/.test(err.message)) {
console.error('The ID/UUID does not identify the expected entity kind; re-check the source URL.');
} else throw err;
} Prevention
- Never pass a moment UUID through a /discuss/ URL or a content ID through a /feed/ URL.
- Keep content IDs (numeric) and moment UUIDs (32 hex chars) in separate variables/fields.
- Verify the entity type by opening the URL in a browser before automation.
When it happens
Trigger: Fetching a detail where the numeric /discuss/<id> actually resolves to a non-content entityType in the API response, or a feed moment UUID resolves to a non-moment entityType; passing a moment UUID via the /discuss/ route or vice versa.
Common situations: Confusing content IDs with moment IDs; a URL pointing to a nowcoder entity type the CLI does not support (e.g. a comment or course item) that shares the same route shape; Nowcoder repurposing entity types in API updates.
Related errors
- Xiaoyuzhou history returned an invalid ${label}; expected se
- 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/9cc12f91a066a736.
Report an issue: GitHub.