{"record":{"id":"f461c889f95d90dc","repo":"jackwener/OpenCLI","slug":"maimai-search-returned-malformed-api-payload","errorCode":null,"errorMessage":"Maimai search returned malformed API payload","messagePattern":"Maimai search returned malformed API payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/maimai/search-talents.js","lineNumber":128,"sourceCode":"        body: JSON.stringify(body),\n      });\n\n      const result = await res.json();\n\n      // Check login status\n      if (res.status === 401 || res.status === 403 || result.error_code === 20002) {\n        throw new Error('需要登录！请先在浏览器中访问 maimai.cn 并登录');\n      }\n\n      if (result.code !== 200 && result.code !== 0) {\n        throw new Error(result.message || result.error || 'API 请求失败');\n      }\n\n      return result;\n    }`);\n\n    if (!data || typeof data !== 'object' || Array.isArray(data)) {\n      throw new CommandExecutionError('Maimai search returned malformed API payload');\n    }\n\n    // Extract talent list from response. Missing list fields mean the API\n    // shape drifted; only an explicit empty array is a true empty result.\n    const talentListCandidates = [\n      data.data?.list,\n      data.data?.talent_list,\n      data.list,\n      data.talent_list,\n    ];\n    const talentList = talentListCandidates.find((value) => Array.isArray(value));\n    if (!talentList) {\n      throw new CommandExecutionError('Maimai search API payload missing talent list');\n    }\n\n    if (talentList.length === 0) {\n      throw new EmptyResultError('maimai search-talents', `未找到匹配 \"${query}\" 的候选人`);\n    }","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/maimai/search-talents.js#L110-L146","documentation":"CommandExecutionError thrown when the value returned from the in-page maimai API call is not a plain object (null, array, or primitive). The CLI treats any non-object payload as evidence that the API contract broke, so it refuses to continue parsing.","triggerScenarios":"The evaluate/injected script returns undefined or a string (e.g. HTML error page, JSON parse produced non-object), or the fetch returned an array at top level.","commonSituations":"Maimai serving an HTML login/anti-bot page instead of JSON, network proxy mangling the response, page navigation interrupting the evaluate call.","solutions":["Log the raw payload before validation to see what actually came back.","Check you are not being redirected to a login/captcha page (sign in to maimai.cn in the browser).","Retry the command; transient proxy or CDN issues can corrupt the payload.","Update the CLI if the endpoint's top-level shape changed."],"exampleFix":"// before\nif (!data || typeof data !== 'object' || Array.isArray(data)) {\n  throw new CommandExecutionError('Maimai search returned malformed API payload');\n}\n// after\nif (!data || typeof data !== 'object' || Array.isArray(data)) {\n  console.error('payload:', typeof data, String(data).slice(0, 200));\n  throw new CommandExecutionError('Maimai search returned malformed API payload — likely an HTML login/captcha page instead of JSON');\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isPlainObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }","tryCatchPattern":"try {\n  const data = await fetchMaimaiSearch(query);\n} catch (e) {\n  if (/malformed API payload/.test(e.message)) {\n    console.error('Non-JSON payload — sign in to maimai.cn and check for captcha pages');\n  } else throw e;\n}","preventionTips":["Verify the browser session renders maimai normally (no captcha/interstitial).","Inspect typeof the evaluate result during development before parsing.","Pin/monitor CLI versions against maimai API changes."],"tags":["api","payload","schema-drift"],"backgroundTag":"malformed-api-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}