{"record":{"id":"255d9205d24b52d6","repo":"jackwener/OpenCLI","slug":"eastmoney-convertible","errorCode":null,"errorMessage":"eastmoney convertible","messagePattern":"eastmoney convertible","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/eastmoney/convertible.js","lineNumber":71,"sourceCode":"  if (!/^\\d+$/.test(raw)) throw new ArgumentError('eastmoney convertible --limit must be an integer between 1 and 100');\n  const parsed = Number(raw);\n  if (parsed < 1 || parsed > 100) throw new ArgumentError('eastmoney convertible --limit must be an integer between 1 and 100');\n  return parsed;\n}\n\nexport function extractConvertibleDiff(data) {\n  if (!data || typeof data !== 'object' || Array.isArray(data)) {\n    throw new CommandExecutionError('eastmoney convertible returned a malformed response envelope');\n  }\n  if (!data.data || typeof data.data !== 'object' || Array.isArray(data.data)) {\n    throw new CommandExecutionError('eastmoney convertible returned a malformed data envelope');\n  }\n  const diff = data.data.diff;\n  if (!Array.isArray(diff)) {\n    throw new CommandExecutionError('eastmoney convertible returned malformed diff data');\n  }\n  if (diff.length === 0) {\n    throw new EmptyResultError('eastmoney convertible');\n  }\n  return diff;\n}\n\n// Map a raw eastmoney clist `diff` item to an output row.\n//\n// #2109: f238 / f239 were previously emitted as `remainingYears` / `ytm`, but\n// cross-verification (12/12 fingerprint hits) shows f239 is the putback trigger\n// price (= convPrice × 0.7) and f238 is the pure-bond premium %. Real YTM /\n// remaining term are not in this response's `fields`; adding the correct f-codes\n// is a follow-up that needs a live push2 field dump cross-checked against jisilu.\nexport function mapConvertibleRow(it, rank) {\n  if (!it || typeof it !== 'object' || Array.isArray(it)) {\n    throw new CommandExecutionError(`eastmoney convertible returned malformed row at rank ${rank}`);\n  }\n  const bondCode = normalizeEastmoneyIdentityString(it.f12, 'f12', '');\n  const bondName = normalizeEastmoneyIdentityString(it.f14, 'f14', bondCode);\n  const stockCode = normalizeEastmoneyIdentityString(it.f232, 'f232', bondCode);","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/eastmoney/convertible.js#L53-L89","documentation":"EmptyResultError('eastmoney convertible') thrown by extractConvertibleDiff (clis/eastmoney/convertible.js:71) when the response parsed fine and `data.data.diff` is an array, but the array has zero elements. The API responded successfully yet no convertible-bond rows matched the query. This is treated as an expected, distinguishable empty result rather than a hard failure.","triggerScenarios":"The push2 clist query with fs=b:MK0354 returns an empty diff array — e.g. the board has no listed convertibles at query time, filters/sort fid produce no rows, or the backend soft-restricts the client and returns an empty success. Raised inside `diff` via extractConvertibleDiff after a valid HTTP 200 + JSON parse.","commonSituations":"Running during market-data maintenance windows; querying from a region/IP where the MK0354 board data is withheld; using an outdated `ut` token that yields empty results instead of an error; genuinely empty board after delistings.","solutions":["Retry later — empty results during off-hours/maintenance often resolve.","Verify with the browser-facing eastmoney convertible bond page that the board currently has listings.","Test the exact push2 URL manually to see whether diff is empty for everyone or just your client (indicates soft block).","Refresh the `ut` token and field list if the API started returning empty payloads for this client.","Handle EmptyResultError distinctly in callers so a truly empty market isn't retried as a failure."],"exampleFix":"// before\nconst rows = await runConvertible();\n// after\ntry {\n  const rows = await runConvertible();\n} catch (e) {\n  if (e.name === 'EmptyResultError') return [];\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// No pre-call validation can predict an empty board; detect post-hoc:\n// EmptyResultError is thrown for diff.length === 0.","typeGuard":null,"tryCatchPattern":"try {\n  const rows = await convertibleDiff();\n} catch (e) {\n  if (e.name === 'EmptyResultError') {\n    return []; // legitimate empty market result — do not retry\n  }\n  throw e;\n}","preventionTips":["Distinguish EmptyResultError from CommandExecutionError — only the latter warrants retries.","Retry empty results at most once with a delay before giving up.","Cross-check the eastmoney web UI to confirm the board is genuinely empty.","Watch for a sudden stream of empty results from one client — a sign of soft blocking."],"tags":["api","empty-result","eastmoney","market-data"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}