{"record":{"id":"286a348936b2a48b","repo":"jackwener/OpenCLI","slug":"trip-com-poisearch-returned-invalid-json-err-in","errorCode":null,"errorMessage":"Trip.com poiSearch returned invalid JSON: ${err instanceof Error ? err.message : String(err)}","messagePattern":"Trip\\.com poiSearch returned invalid JSON: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/trip/utils.js","lineNumber":851,"sourceCode":"            headers: { 'content-type': 'application/json', currency: 'USD' },\n            body: JSON.stringify({\n                key: keyword,\n                mode: '0',\n                tripType: 'RT',\n                Head: { Currency: 'USD', Locale: 'en-US', Source: 'ONLINE', Channel: 'EnglishSite', ClientID: 'opencli-trip' },\n            }),\n        });\n    } catch (err) {\n        throw new CommandExecutionError(`Trip.com poiSearch fetch failed: ${err instanceof Error ? err.message : String(err)}`);\n    }\n    if (!response.ok) {\n        throw new CommandExecutionError(`Trip.com poiSearch failed with status ${response.status}`);\n    }\n    let payload;\n    try {\n        payload = await response.json();\n    } catch (err) {\n        throw new CommandExecutionError(`Trip.com poiSearch returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);\n    }\n    if (!Array.isArray(payload?.results)) {\n        throw new CommandExecutionError('Trip.com poiSearch returned malformed payload: missing results array');\n    }\n    return payload.results;\n}\n\n/**\n * Flatten POI results into a flat suggestion list: each top-level city keeps its\n * own row, and its `childResults` (nearby airports) follow, so a single search\n * surfaces both the city id and the airport codes.\n */\nexport function flattenPoiResults(results) {\n    const rows = [];\n    for (const result of results) {\n        if (!result || typeof result !== 'object') continue;\n        rows.push(result);\n        if (Array.isArray(result.childResults)) {","sourceCodeStart":833,"sourceCodeEnd":869,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/utils.js#L833-L869","documentation":"fetchPoiSearch calls response.json() and re-throws any parse failure as CommandExecutionError with 'Trip.com poiSearch returned invalid JSON: ...'. This means the server responded with a non-JSON body (HTML error page, empty body, truncated response) despite a successful status code.","triggerScenarios":"Trip.com returns an HTML challenge/login page with 200 status; response body truncated mid-stream; empty body on 204; CDN serving a cached HTML error page; charset/BOM issues in the body.","commonSituations":"Anti-bot interstitials returned with 200; proxy servers injecting their own HTML error pages; flaky mobile connections truncating responses; API returning plain-text rate-limit notices.","solutions":["Inspect the raw response body (curl the endpoint) to see what was actually returned","Handle anti-bot challenges: the HTML body usually indicates Trip.com wants verification or different headers","Retry — truncated responses are often transient","Add a proxy/debug layer (mitm, request logging) to capture the exact body and headers"],"exampleFix":"// before\nconst results = await fetchPoiSearch(...)  // got HTML instead of JSON\n// after\ntry { const r = await fetchPoiSearch(...) } catch (e) {\n  if (String(e.message).includes('invalid JSON')) { console.error('non-JSON body — check for anti-bot page'); }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"const looksLikeJson = (s) => typeof s === 'string' && s.trimStart().startsWith('{');","tryCatchPattern":"try {\n  const results = await searchAttractions(keyword);\n} catch (e) {\n  if (/poiSearch returned invalid JSON/.test(e.message)) {\n    console.error('Non-JSON body received — likely anti-bot page or proxy HTML. Inspect with curl.');\n    return retryAfterDelay(() => searchAttractions(keyword), 5000);\n  }\n  throw e;\n}","preventionTips":["Curl the endpoint to know what a healthy body looks like","Detect anti-bot HTML challenges and rotate headers/cookies/IPs","Retry truncated responses — they are often transient","Route through a debug proxy when diagnosing recurring body issues"],"tags":["http","json-parsing","api-response"],"backgroundTag":"invalid-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}