{"record":{"id":"91fe4d82d1f8e152","repo":"jackwener/OpenCLI","slug":"kimi-usage-returned-malformed-payload-missing","errorCode":null,"errorMessage":"kimi usage returned malformed payload: missing \"${name}\"","messagePattern":"kimi usage returned malformed payload: missing \"(.+?)\"","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/kimi/usage.js","lineNumber":40,"sourceCode":"    const m = String(value || '').match(/(\\d+(?:\\.\\d+)?)\\s*%/);\n    return m ? Number(m[1]) : null;\n}\n\nfunction normalize(s) {\n    return String(s || '').trim();\n}\n\nfunction requireFinite(value, name) {\n    if (!Number.isFinite(value)) {\n        throw new CommandExecutionError(`kimi usage returned malformed payload: missing or invalid \"${name}\"`);\n    }\n    return value;\n}\n\nfunction requireText(value, name) {\n    const text = normalize(value);\n    if (!text) {\n        throw new CommandExecutionError(`kimi usage returned malformed payload: missing \"${name}\"`);\n    }\n    return text;\n}\n\ncli({\n    site: 'kimi',\n    name: 'usage',\n    access: 'read',\n    description: 'Read Kimi membership quota usage from the subscription page: total usage, rate limits, gift quota, and booster balance.',\n    domain: KIMI_DOMAIN,\n    strategy: Strategy.COOKIE,\n    browser: true,\n    siteSession: 'persistent',\n    navigateBefore: true,\n    args: [],\n    columns: [\n        'membershipName',\n        'membershipValidUntil',","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/kimi/usage.js#L22-L58","documentation":"requireText in clis/kimi/usage.js validates string fields from Kimi's usage payload. After trim/normalize, if the value is empty (undefined, null, or whitespace), it throws CommandExecutionError saying the payload is missing that field. It ensures reported usage rows always carry non-empty values for textual fields like model name or plan name.","triggerScenarios":"Calling the kimi usage command when a textual field (e.g. plan, model, period label) is absent or empty string in Kimi's usage payload.","commonSituations":"Kimi renamed/moved a label in the usage UI; account without an assigned plan so the field is blank; selector matched the wrong node yielding empty text; i18n change moved the text elsewhere.","solutions":["Retry — intermittent rendering can leave text nodes empty.","Log in again / ensure the account has an active plan so all fields are present.","Update the library's usage parser to Kimi's current markup/endpoint.","Inspect the raw payload to identify the empty field and adjust extraction."],"exampleFix":"// before\nconst plan = requireText(data.plan, 'plan'); // throws when ''\n// after\nconst plan = requireText(data.plan || data.planName || 'unknown', 'plan');","handlingStrategy":"type-guard","validationCode":"for (const k of ['plan','model']) {\n  if (!String(payload?.[k] ?? '').trim()) throw new Error(`usage payload field \"${k}\" is empty`);\n}","typeGuard":"const isNonEmptyText = (v) => typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try {\n  const usage = await run('kimi', 'usage');\n} catch (e) {\n  if (/malformed payload: missing/.test(e.message)) {\n    const field = e.message.match(/missing \"(.+)\"/)?.[1];\n    console.warn(`Kimi usage lacks field ${field}; continuing with defaults`);\n    return null; // fallback path\n  }\n  throw e;\n}","preventionTips":["Coerce possibly-blank scraped text with defaults before validation.","Check that the account has an active plan so textual fields are populated.","Update extraction selectors when Kimi's usage UI markup changes."],"tags":["payload-validation","usage","kimi"],"backgroundTag":"malformed-api-payload","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}