jackwener/OpenCLI · error · CommandExecutionError
Nowcoder detail returned malformed post data
Error message
Nowcoder detail returned malformed post data
What it means
projectNowcoderDetail validates the JSON returned by the Nowcoder detail API before projecting it into the CLI output. It requires the payload to be an object containing a frequencyData object (the engagement-metrics sub-object). If the API returns null, an array, or an object without frequencyData, the library considers the response malformed and throws this CommandExecutionError rather than producing partially-filled output.
Source
Thrown at clis/nowcoder/posts.js:202
url = new URL(value);
}
catch {
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}`,View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the post still exists and is publicly viewable in a browser while logged in.
- Log in to Nowcoder (the CLI uses your browser session) and retry — restricted posts may return partial data.
- Retry later in case of transient API issues; if persistent, report the schema drift since the library may need updating.
- Re-check that the correct content ID / moment UUID was passed, since wrong IDs can resolve to empty payloads.
Example fix
// before nowcoder detail 99999999999 // deleted/nonexistent post -> malformed data // after nowcoder detail 70123456 // verify the post loads at nowcoder.com/discuss/70123456 first
Defensive patterns
Strategy: try-catch
Type guard
function looksLikeNowcoderDetail(data) {
return data !== null && typeof data === 'object' && !Array.isArray(data)
&& typeof data.frequencyData === 'object' && data.frequencyData !== null;
} Try / catch
try {
const post = await nowcoderDetail(id);
} catch (err) {
if (err instanceof CommandExecutionError && /malformed post data/.test(err.message)) {
console.error('Post may be deleted, private, or schema-drifted; verify it in a browser:', id);
} else throw err;
} Prevention
- Confirm the post loads in a logged-in browser before scripting against it.
- Re-verify IDs/UUIDs after posts are deleted or merged.
- Keep the CLI/library updated for Nowcoder API schema changes.
- Treat repeated malformed-data errors for the same ID as 'post gone' rather than retrying forever.
When it happens
Trigger: The detail endpoint responded with a JSON body that is not a record or lacks the frequencyData field — e.g. the post was deleted or made private and the API returned an empty/null data payload, the endpoint changed shape, or an error page was returned with HTTP 200.
Common situations: Viewing a recently deleted or hidden post; a post that requires login to view; Nowcoder changing its internal API response schema; hitting a different regional endpoint or anti-bot interstitial that returns HTML/empty JSON.
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
- Bilibili ${label} API returned a malformed payload
- Bilibili ${label} API failed: ${message} (${payload.code})
- 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/783c74e94fed6427.
Report an issue: GitHub.