{"record":{"id":"68f40e8d5888d57b","repo":"jackwener/OpenCLI","slug":"command-exec","errorCode":"COMMAND_EXEC","errorMessage":"ctrip suggest returned invalid JSON: ${err instanceof Error ? err.message : String(err)}","messagePattern":"ctrip suggest returned invalid JSON: (.+?)","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/utils.js","lineNumber":89,"sourceCode":"    } catch (err) {\n        throw new CliError(\n            'FETCH_ERROR',\n            `ctrip suggest fetch failed: ${err instanceof Error ? err.message : String(err)}`,\n            'Check your network connection and retry',\n        );\n    }\n    if (!response.ok) {\n        throw new CliError(\n            'FETCH_ERROR',\n            `ctrip suggest failed with status ${response.status}`,\n            'Retry the command or verify ctrip.com is reachable',\n        );\n    }\n    let payload;\n    try {\n        payload = await response.json();\n    } catch (err) {\n        throw new CliError(\n            'COMMAND_EXEC',\n            `ctrip suggest returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`,\n            'Ctrip may have changed the endpoint response format; retry later',\n        );\n    }\n    if (payload && payload.Result === false) {\n        const code = payload.ErrorCode ?? 'unknown';\n        throw new CliError(\n            'COMMAND_EXEC',\n            `ctrip suggest API returned Result=false (ErrorCode=${code})`,\n            'Verify keyword and retry; this typically means upstream rejected the query envelope',\n        );\n    }\n    if (!payload || typeof payload !== 'object' || !payload.Response || typeof payload.Response !== 'object' || !Array.isArray(payload.Response.searchResults)) {\n        throw new CliError(\n            'COMMAND_EXEC',\n            'ctrip suggest returned malformed response shape: Response.searchResults is missing or not an array',\n            'Ctrip may have changed the endpoint response format; retry later',","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/utils.js#L71-L107","documentation":"fetchSuggest calls response.json() and wraps parse failures in a COMMAND_EXEC CliError. This fires when the HTTP response body is not valid JSON — typically an HTML error page, a captcha/anti-bot interstitial, or an empty body returned with a 200 status.","triggerScenarios":"fetchSuggest(query, searchType) gets a 200 response whose body fails JSON.parse — e.g. Ctrip returned an HTML block page, a login wall, or truncated/garbled content.","commonSituations":"Anti-bot gateway serves an HTML challenge with status 200; CDN error page; response interrupted mid-transfer; Ctrip A/B testing a new response format.","solutions":["Inspect the raw response body (log response.text() in a local copy) to see what was actually returned","Retry later — often a transient anti-bot or CDN issue","Check if Ctrip changed the endpoint response format","Slow down request rate to avoid triggering anti-bot pages"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const rows = await fetchSuggest(keyword, 'D');\n} catch (err) {\n  if (err.code === 'COMMAND_EXEC' && /invalid JSON/.test(err.message)) {\n    // capture raw body via a debug fetch to diagnose (captcha page? HTML error?)\n  }\n  throw err;\n}","preventionTips":["Log response bodies when debugging to spot HTML anti-bot pages","Reduce request frequency to avoid triggering challenges","Retry later on transient CDN/anti-bot issues","Pin and review parsing code when Ctrip changes formats"],"tags":["json","parsing","http"],"backgroundTag":"invalid-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}