jackwener/OpenCLI · error · CommandExecutionError
Nowcoder detail returned mismatched moment entity ids
Error message
Nowcoder detail returned mismatched moment entity ids
What it means
For moment targets, projectNowcoderDetail cross-checks that the moment's entityId equals the API record's id field. In Nowcoder's moment model the entityId and id should agree; if they diverge, the response is internally inconsistent and the library refuses to project it with this CommandExecutionError.
Source
Thrown at clis/nowcoder/posts.js:210
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,
likes: metric(data.frequencyData, 'likeCnt'),
comments: metric(data.frequencyData, 'commentCnt'),
views: metric(data.frequencyData, 'viewCnt'),
time: isoTime(isContent ? data.createTime : data.createdAt, `${target.post_type} timestamp`),
location: optionalText(data.ip4Location, `${target.post_type} location`),View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the fetch — transient inconsistency often resolves once the backend settles.
- Verify the moment loads correctly on www.nowcoder.com in a browser; if not, the post itself may be broken.
- If persistent, treat it as a Nowcoder API schema change and update the library's moment projection logic.
- Consider fetching the moment via its canonical UUID again to get a fresh record.
Example fix
// before
// library assumes moment entityId === id
if (!isContent && entityId !== requiredId(data.id, 'moment id')) throw new CommandExecutionError('Nowcoder detail returned mismatched moment entity ids');
// after
// tolerate/normalize the divergence if Nowcoder changed semantics
const id = isContent ? requiredId(data.id, 'content id') : entityId; Defensive patterns
Strategy: retry
Type guard
function isConsistentMoment(data) {
return typeof data?.entityId !== 'undefined' && typeof data?.id !== 'undefined'
&& String(data.entityId) === String(data.id);
} Try / catch
async function fetchMomentWithRetry(uuid, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try { return await nowcoderDetail(uuid); }
catch (err) {
const transient = err instanceof CommandExecutionError && /mismatched moment entity ids/.test(err.message);
if (!transient || i === attempts - 1) throw err;
await new Promise(r => setTimeout(r, 2000 * (i + 1)));
}
}
} Prevention
- Retry with backoff — moment records can be transiently inconsistent right after edits.
- Verify the moment in a browser; if broken there too, the post itself is the problem.
- Update the library if Nowcoder changes moment entityId/id semantics permanently.
When it happens
Trigger: Fetching a /feed/main/detail/<uuid> moment where the returned payload has entityId !== id — an API-side inconsistency, partial update, or schema change for moment records.
Common situations: Newly created or edited moments whose API record is momentarily inconsistent; Nowcoder backend schema drift; API versions returning different field semantics for moments.
Related errors
- 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
- Bilibili ${label} API did not return top_replies
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/d793f98f0b4d88de.
Report an issue: GitHub.