jackwener/OpenCLI · error · CommandExecutionError

Nowcoder returned a malformed

Error message

Nowcoder returned a malformed ${label}

What it means

This library validates every identifier that comes back from Nowcoder API payloads before exposing it. requiredId() accepts either a safe integer or a numeric string matching /^[1-9]\d*$/, and throws CommandExecutionError('Nowcoder returned a malformed <label>') when the value is anything else (missing, null, an object, a non-numeric or zero-padded string). It signals that Nowcoder returned data whose shape the library does not recognize, so the raw value is never propagated.

Solutions

  1. Inspect the raw HTTP payload for the item whose <label> is cited (e.g. 'content id', 'userBrief.userId') and confirm the field is a positive integer or numeric string
  2. Update the library or fix the endpoint URL — the API schema likely changed
  3. Ensure the Nowcoder session is valid (log in); degraded/unauthenticated payloads often lack proper id fields
  4. Pre-filter feed records, dropping items that lack the expected id fields before calling the projection functions

Example fix

// before (raw value passed straight through)
const id = post.id;
// after (pre-validate in caller code)
const id = /^[1-9]\d*$/.test(String(post.id)) ? String(post.id) : null;
if (id == null) continue; // skip malformed feed item
Defensive patterns

Strategy: validation

Validate before calling

function isValidNowcoderId(v) {
  const s = typeof v === 'number' && Number.isSafeInteger(v) ? String(v) : v;
  return typeof s === 'string' && /^[1-9]\d*$/.test(s);
}
// run before processing: records.every(r => isValidNowcoderId(r.data?.contentData?.id))

Type guard

function isNowcoderId(value) {
  const id = typeof value === 'number' && Number.isSafeInteger(value) ? String(value) : value;
  return typeof id === 'string' && /^[1-9]\d*$/.test(id);
}

Try / catch

try {
  const rows = projectNowcoderFeed(records, limit, source, wrapped);
} catch (err) {
  if (err instanceof CommandExecutionError && /malformed/.test(err.message)) {
    console.warn('Skipping malformed Nowcoder payload:', err.message);
    // re-fetch or skip the offending record
  } else throw err;
}

Prevention

When it happens

Trigger: A feed or detail response row has userBrief.userId, contentData.id/contentId/entityId, or momentData.id/contentId that is undefined, null, 0, a negative number, a float, a non-numeric string, or an object — e.g. Nowcoder changed its API field names, returned an error/empty item inside a list, or a wrapped record was unwrapped incorrectly. Called from authorId/authorFields/id/projectFeedData/entityId/projectNowcoderDetail paths.

Common situations: Nowcoder silently changes its JSON schema (field renamed from userId, id now a string with a prefix); an item in the feed list is a stub/ad payload without ids; scraping without login returns degraded payloads; a moment post's id field is absent for deleted content; using an unofficial/outdated endpoint that no longer matches the expected shape.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at clis/nowcoder/posts.js:21

    AuthRequiredError,
    CommandExecutionError,
    EmptyResultError,
} from '@jackwener/opencli/errors';

const CONTENT_FEED_TYPE = 250;
const CONTENT_ENTITY_TYPE = 8;
const MOMENT_TYPE = 74;
const UUID_PATTERN = /^[0-9a-f]{32}$/i;
const NUMERIC_ID_PATTERN = /^[1-9]\d*$/;
const NAMED_ENTITIES = { nbsp: ' ', amp: '&', lt: '<', gt: '>', quot: '"', apos: "'" };

function isRecord(value) {
    return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}

function requiredId(value, label) {
    const id = typeof value === 'number' && Number.isSafeInteger(value) ? String(value) : value;
    if (typeof id !== 'string' || !NUMERIC_ID_PATTERN.test(id)) throw new CommandExecutionError(`Nowcoder returned a malformed ${label}`);
    return id;
}

function requiredUuid(value, label) {
    if (typeof value !== 'string' || !UUID_PATTERN.test(value)) throw new CommandExecutionError(`Nowcoder returned a malformed ${label}`);
    return value.toLowerCase();
}

function optionalText(value, label) {
    if (value == null) return '';
    if (typeof value !== 'string') throw new CommandExecutionError(`Nowcoder returned a malformed ${label}`);
    return value.trim();
}

function decodeEntities(value) {
    return value.replace(/&(#x[0-9a-f]+|#\d+|nbsp|amp|lt|gt|quot|apos);/gi, (match, entity) => {
        const normalized = entity.toLowerCase();
        if (NAMED_ENTITIES[normalized] != null) return NAMED_ENTITIES[normalized];

View on GitHub (pinned to 49907e53dc)