jackwener/OpenCLI · error · CommandExecutionError

${label} returned a malformed numeric field

Error message

${label} returned a malformed numeric field

What it means

readOptionalNumber validates optional numeric fields coming from Juejin API rows (feed items, hot items). If a field is present (not null/undefined) but Number() yields NaN/Infinity — e.g. a string like 'abc' or an object — it throws CommandExecutionError because the API returned data that does not fit the expected numeric schema. This guards downstream mapping code from silently producing NaN values.

Source

Thrown at clis/juejin/utils.js:153

    if (payload.data.length === 0) {
        throw new EmptyResultError(label, `${label} returned no articles.`);
    }
    return payload.data;
}

function readArticleId(value, label) {
    const id = String(value ?? '').trim();
    if (!JUEJIN_ID.test(id)) {
        throw new CommandExecutionError(`${label} returned a malformed article id`);
    }
    return id;
}

function readOptionalNumber(value, label) {
    if (value == null) return null;
    const n = Number(value);
    if (!Number.isFinite(n)) {
        throw new CommandExecutionError(`${label} returned a malformed numeric field`);
    }
    return n;
}

/** Map a recommend-feed row (`item_info.article_info` / `author_user_info`) to a flat shape. */
export function mapFeedItem(row, rank) {
    const info = row?.item_info ?? {};
    const article = info.article_info ?? {};
    const author = info.author_user_info ?? {};
    const tags = Array.isArray(info.tags)
        ? info.tags.map(t => t?.tag_name).filter(Boolean).slice(0, 6).join(', ')
        : '';
    const articleId = readArticleId(article.article_id, 'juejin recommend');
    return {
        rank,
        article_id: articleId,
        title: String(article.title ?? '').trim(),
        brief: String(article.brief_content ?? '').trim(),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check the raw API row (curl https://api.juejin.cn/... or log `value`) to see the actual field value
  2. Re-run the command — the malformed value is often transient garbage from one row
  3. Update the adapter's mapFeedItem/mapHotItem if Juejin changed the field format, adding normalization (e.g. parse '1.2w')
  4. If a specific field is chronically non-numeric, pass null/omit it instead of feeding it to readOptionalNumber

Example fix

// before
readOptionalNumber(row.item_info.article_info.view_count, 'view_count') // value = '1.2万' -> throws
// after
function parseCNNumber(v) {
  if (v == null) return null;
  if (typeof v === 'string') {
    const m = v.match(/^([\d.]+)([万w]?)$/i);
    if (m) return Number(m[1]) * (m[2] ? 10000 : 1);
  }
  return readOptionalNumber(v, 'view_count');
}
Defensive patterns

Strategy: validation

Validate before calling

function safeNumber(v) {
  if (v == null) return null;
  const n = Number(v);
  return Number.isFinite(n) ? n : null;
}
const views = safeNumber(row?.item_info?.article_info?.view_count);
if (views === null && row?.item_info?.article_info?.view_count != null) {
  console.warn('skipping malformed row', row.item_info.article_id);
}

Type guard

function isNumericField(v) {
  return v == null || (typeof v === 'number' && Number.isFinite(v)) ||
         (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v)));
}

Try / catch

try {
  const item = mapFeedItem(row, rank);
} catch (e) {
  if (/malformed numeric field/.test(e.message)) {
    console.warn(`skip row ${row?.item_info?.article_id}: ${e.message}`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: mapFeedItem or mapHotItem passes an `article_info`/`author_user_info` field (e.g. view_count, digg_count) that is a non-numeric string or object instead of a number or numeric string; Juejin changed its API response shape; the field is a placeholder like '-' or ''.

Common situations: Juejin ships an API schema change (field becomes a formatted string like '1.2w'); a partially-degraded/edge response row has nulls coerced oddly; scraping a preview/test endpoint with mock data.

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/7546fe6020cf0733. Report an issue: GitHub.