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

  1. Verify the post still exists and is publicly viewable in a browser while logged in.
  2. Log in to Nowcoder (the CLI uses your browser session) and retry — restricted posts may return partial data.
  3. Retry later in case of transient API issues; if persistent, report the schema drift since the library may need updating.
  4. 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

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

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/783c74e94fed6427. Report an issue: GitHub.