{"record":{"id":"8cb63df8332e0bb4","repo":"jackwener/OpenCLI","slug":"trip-com-poisearch-returned-malformed-payload-mis","errorCode":null,"errorMessage":"Trip.com poiSearch returned malformed payload: missing results array","messagePattern":"Trip\\.com poiSearch returned malformed payload: missing results array","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/trip/utils.js","lineNumber":854,"sourceCode":"                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)) {\n            for (const child of result.childResults) {\n                if (child && typeof child === 'object') rows.push(child);\n            }","sourceCodeStart":836,"sourceCodeEnd":872,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/utils.js#L836-L872","documentation":"fetchPoiSearch expects the parsed JSON body to contain a results array (payload?.results). If the JSON parsed fine but results is missing or not an array, it throws CommandExecutionError with 'Trip.com poiSearch returned malformed payload: missing results array'. This indicates the API contract changed or an error envelope was returned with a success status.","triggerScenarios":"Trip.com returns {\"ResponseStatus\":...,\"error\":...} instead of results; API schema update renames or nests the results field; request body fields wrong so the server returns an empty error-shape payload.","commonSituations":"Trip.com silently changing their internal API schema; anti-bot or session-expiry envelopes that still return 200; wrong locale/currency parameters causing an unexpected response shape; caching layers serving stale schemas.","solutions":["Log the full parsed payload to see what shape actually came back","Check for an error/status field inside the payload (e.g. ResponseStatus) and act on it","Verify your request body/params match the current expected poiSearch contract","Update the library/parser if Trip.com changed the response schema"],"exampleFix":"// before\nif (!Array.isArray(payload?.results)) throw ...   // payload = {ResponseStatus:{...}}\n// after\nconst results = payload?.results ?? payload?.data?.results;\nif (!Array.isArray(results)) throw new Error('payload: ' + JSON.stringify(payload).slice(0,500))","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"function isPoiResults(payload) {\n  return payload !== null && typeof payload === 'object' && Array.isArray(payload.results);\n}","tryCatchPattern":"try {\n  const results = await searchAttractions(keyword);\n} catch (e) {\n  if (/malformed payload: missing results array/.test(e.message)) {\n    console.error('Trip.com payload schema changed or error envelope returned. Dump payload and check for ResponseStatus/error field.');\n  }\n  throw e;\n}","preventionTips":["Log the full payload when the shape check fails to spot error envelopes","Check for ResponseStatus/error fields before assuming success","Pin/monitor the library version against Trip.com schema drift","Validate alternate field locations (e.g. payload.data.results) defensively"],"tags":["api-response","schema-validation","contract"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}