{"record":{"id":"d793f98f0b4d88de","repo":"jackwener/OpenCLI","slug":"nowcoder-detail-returned-mismatched-moment-entity","errorCode":null,"errorMessage":"Nowcoder detail returned mismatched moment entity ids","messagePattern":"Nowcoder detail returned mismatched moment entity ids","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/nowcoder/posts.js","lineNumber":210,"sourceCode":"        throw new ArgumentError('nowcoder detail only accepts canonical https://www.nowcoder.com post URLs');\n    }\n    const content = url.pathname.match(/^\\/discuss\\/([1-9]\\d*)\\/?$/);\n    if (content) return { post_type: 'content', value: content[1] };\n    const moment = url.pathname.match(/^\\/feed\\/main\\/detail\\/([0-9a-f]{32})\\/?$/i);\n    if (moment) return { post_type: 'moment', value: moment[1].toLowerCase() };\n    throw new ArgumentError('Unsupported Nowcoder URL; expected /discuss/<content-id> or /feed/main/detail/<moment-uuid>');\n}\n\nexport function projectNowcoderDetail(data, target) {\n    if (!isRecord(data) || !isRecord(data.frequencyData)) throw new CommandExecutionError('Nowcoder detail returned malformed post data');\n    const isContent = target.post_type === 'content';\n    const expectedEntityType = isContent ? CONTENT_ENTITY_TYPE : MOMENT_TYPE;\n    if (data.entityType !== expectedEntityType) throw new CommandExecutionError('Nowcoder detail returned a mismatched post entity type');\n    const uuid = requiredUuid(data.uuid, `${target.post_type} uuid`);\n    const entityId = requiredId(data.entityId, `${target.post_type} entity id`);\n    const id = isContent ? requiredId(data.id, 'content id') : uuid;\n    if (isContent ? id !== target.value : uuid !== target.value) throw new CommandExecutionError('Nowcoder detail returned a different post identity');\n    if (!isContent && entityId !== requiredId(data.id, 'moment id')) throw new CommandExecutionError('Nowcoder detail returned mismatched moment entity ids');\n    const expectedAuthorId = isContent ? data.authorId : data.userId;\n    const body = cleanBody(isContent ? data.richText : data.content, `${target.post_type} detail body`);\n    return {\n        post_type: target.post_type,\n        id,\n        uuid,\n        entity_id: entityId,\n        url: isContent\n            ? `https://www.nowcoder.com/discuss/${id}`\n            : `https://www.nowcoder.com/feed/main/detail/${uuid}`,\n        title: optionalText(data.title, `${target.post_type} title`) || '(untitled)',\n        ...authorFields(data.userBrief, expectedAuthorId, target.post_type),\n        content: body,\n        likes: metric(data.frequencyData, 'likeCnt'),\n        comments: metric(data.frequencyData, 'commentCnt'),\n        views: metric(data.frequencyData, 'viewCnt'),\n        time: isoTime(isContent ? data.createTime : data.createdAt, `${target.post_type} timestamp`),\n        location: optionalText(data.ip4Location, `${target.post_type} location`),","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/nowcoder/posts.js#L192-L228","documentation":"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.","triggerScenarios":"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.","commonSituations":"Newly created or edited moments whose API record is momentarily inconsistent; Nowcoder backend schema drift; API versions returning different field semantics for moments.","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."],"exampleFix":"// before\n// library assumes moment entityId === id\nif (!isContent && entityId !== requiredId(data.id, 'moment id')) throw new CommandExecutionError('Nowcoder detail returned mismatched moment entity ids');\n// after\n// tolerate/normalize the divergence if Nowcoder changed semantics\nconst id = isContent ? requiredId(data.id, 'content id') : entityId;","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isConsistentMoment(data) {\n  return typeof data?.entityId !== 'undefined' && typeof data?.id !== 'undefined'\n    && String(data.entityId) === String(data.id);\n}","tryCatchPattern":"async function fetchMomentWithRetry(uuid, attempts = 3) {\n  for (let i = 0; i < attempts; i++) {\n    try { return await nowcoderDetail(uuid); }\n    catch (err) {\n      const transient = err instanceof CommandExecutionError && /mismatched moment entity ids/.test(err.message);\n      if (!transient || i === attempts - 1) throw err;\n      await new Promise(r => setTimeout(r, 2000 * (i + 1)));\n    }\n  }\n}","preventionTips":["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."],"tags":["api-response","data-integrity","schema-validation"],"backgroundTag":"malformed-api-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}