jackwener/OpenCLI · error · CommandExecutionError

eastmoney convertible returned malformed ${field} for ${bond

Error message

eastmoney convertible returned malformed ${field} for ${bondCode || 'unknown bond'}

What it means

normalizeEastmoneyNumeric() validates quote metrics from the convertible-bond API. It accepts finite numbers and the literal '-' (Eastmoney's marker for temporarily unavailable data), and throws CommandExecutionError for anything else — meaning a field the code expects to be numeric came back as a string, null, undefined, NaN, or an object.

Source

Thrown at clis/eastmoney/convertible.js:33

  value:         { fid: 'f236', order: 'desc' }, // 转股价值
  // #2109: f239 is the putback trigger price (= convPrice × 0.7), not YTM.
  // Renamed so `--sort` no longer claims to order by a value it doesn't hold.
  'put-trigger': { fid: 'f239', order: 'desc' }, // 回售触发价
};

const NUMERIC_FIELDS = [
  'f2', 'f3', 'f229', 'f230', 'f235', 'f236', 'f237', 'f238', 'f239',
];

function isEastmoneyScalar(value) {
  return typeof value === 'string' || typeof value === 'number';
}

function normalizeEastmoneyNumeric(value, field, bondCode) {
  if (typeof value === 'number' && Number.isFinite(value)) return value;
  // Eastmoney uses "-" for temporarily unavailable quote metrics.
  if (value === '-') return value;
  throw new CommandExecutionError(`eastmoney convertible returned malformed ${field} for ${bondCode || 'unknown bond'}`);
}

function normalizeEastmoneyString(value, field, bondCode) {
  if (isEastmoneyScalar(value)) return String(value);
  throw new CommandExecutionError(`eastmoney convertible returned malformed ${field} for ${bondCode || 'unknown bond'}`);
}

function normalizeEastmoneyIdentityString(value, field, bondCode) {
  if (typeof value === 'string' && value.trim()) return value;
  throw new CommandExecutionError(`eastmoney convertible returned malformed ${field} for ${bondCode || 'unknown bond'}`);
}

export function parseConvertibleLimit(value) {
  if (value === undefined || value === null || value === '') return 20;
  if (typeof value === 'number') {
    if (Number.isInteger(value) && value >= 1 && value <= 100) return value;
    throw new ArgumentError('eastmoney convertible --limit must be an integer between 1 and 100');
  }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the raw API row for the offending field and confirm its current type.
  2. If Eastmoney now sends numeric strings, preprocess with Number(value) before mapping, or relax the check.
  3. Treat the throw as data-quality signal: catch CommandExecutionError, log the bond code + field, and skip that row.
  4. Pin/verify against the current Eastmoney convertible API response format.

Example fix

// before
const price = normalizeEastmoneyNumeric(row.PRICE, 'price', code);
// after
const rawPrice = row.PRICE === '-' ? row.PRICE : (row.PRICE == null ? row.PRICE : Number(row.PRICE));
const price = normalizeEastmoneyNumeric(rawPrice, 'price', code);
Defensive patterns

Strategy: type-guard

Validate before calling

const isOkNumeric = (v) => (typeof v === 'number' && Number.isFinite(v)) || v === '-';
if (!isOkNumeric(row.PRICE)) console.warn('price unavailable for', row.SECURITY_CODE);

Type guard

const isEastmoneyNumeric = (v) => (typeof v === 'number' && Number.isFinite(v)) || v === '-';

Try / catch

try {
  const mapped = mapConvertibleRow(row);
} catch (e) {
  if (e instanceof CommandExecutionError && /malformed/.test(e.message)) {
    console.warn(`Skipping row with bad numeric field: ${e.message}`);
  } else throw e;
}

Prevention

When it happens

Trigger: A row field (e.g. price, premium rate, volume) is null/undefined, a numeric-looking string like '123.45', NaN, or a nested object — anything not a finite number or '-'. Called from mapConvertibleRow for each numeric column.

Common situations: Eastmoney changes field semantics or units and returns strings; suspended bonds return null instead of '-'; a schema drift makes a column an object after a site update.

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/8c66da11e71271b0. Report an issue: GitHub.