jackwener/OpenCLI · error · CommandExecutionError
Trip.com package search returned malformed payload: missing
Error message
Trip.com package search returned malformed payload: missing grouplist array
What it means
The Trip.com package-search adapter parsed the HTTP response successfully as JSON, but the resulting object did not contain a `grouplist` array, which is the field the adapter relies on for package flight groups. This is thrown as a CommandExecutionError because the underlying command (an upstream Trip.com API/scrape call) executed but produced an unexpected shape. It signals an upstream contract change, an anti-bot/error page rendered as JSON, or a non-200 body that still parses as JSON.
Source
Thrown at clis/trip/utils.js:967
response = await fetch(PACKAGE_SEARCH_ENDPOINT, {
method: 'POST',
headers: { 'content-type': 'application/json', currency: 'USD' },
body: JSON.stringify(body),
});
} catch (err) {
throw new CommandExecutionError(`Trip.com package search fetch failed: ${err instanceof Error ? err.message : String(err)}`);
}
if (!response.ok) {
throw new CommandExecutionError(`Trip.com package search failed with status ${response.status}`);
}
let payload;
try {
payload = await response.json();
} catch (err) {
throw new CommandExecutionError(`Trip.com package search returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
}
if (!Array.isArray(payload?.grouplist)) {
throw new CommandExecutionError('Trip.com package search returned malformed payload: missing grouplist array');
}
return payload.grouplist;
}
/**
* Project a package flight group into the stable adapter column shape. A group's
* `flightlist` is the itinerary legs (one for a nonstop), so the route summary
* reads the departure off the first leg and the arrival off the last, with the
* leg count minus one as the stop count. `price` is the per-person package
* starting fare (`policylist[0].price.price`); missing values stay `null`.
*/
export function mapPackageRow(group, index) {
const legs = Array.isArray(group?.flightlist) ? group.flightlist : [];
const first = legs[0] || {};
const last = legs[legs.length - 1] || {};
const binfo = first.binfo || {};
const price = group?.policylist?.[0]?.price?.price;
const str = (v) => (v == null || v === '') ? null : String(v).replace(/\s+/g, ' ').trim();View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the search with different dates/route to rule out an empty upstream result before assuming a schema change.
- Log the raw payload (before the grouplist check) to see what Trip.com actually returned (error envelope, CAPTCHA, or schema change).
- Check for an updated version of the opencli trip adapter that matches the current Trip.com response schema.
- If Trip.com changed the schema, update fetchPackageSearch to read the new field name and re-validate with Array.isArray.
- Retry later or from a different network if anti-bot responses are suspected.
Example fix
// before
if (!Array.isArray(payload?.grouplist)) {
throw new CommandExecutionError('Trip.com package search returned malformed payload: missing grouplist array');
}
return payload.grouplist;
// after
const groups = payload?.grouplist ?? payload?.data?.grouplist;
if (!Array.isArray(groups)) {
throw new CommandExecutionError(`Trip.com package search returned malformed payload: missing grouplist array (keys: ${Object.keys(payload ?? {}).join(',')})`);
}
return groups; Defensive patterns
Strategy: validation
Validate before calling
const payload = await response.json().catch(() => null);
if (!payload || typeof payload !== 'object' || !Array.isArray(payload.grouplist)) {
throw new Error('Trip.com package search payload missing grouplist array');
} Type guard
function hasGrouplist(p) {
return typeof p === 'object' && p !== null && Array.isArray(p.grouplist);
} Try / catch
try {
const groups = await fetchPackageSearch(params);
} catch (err) {
if (err instanceof CommandExecutionError && err.message.includes('malformed payload')) {
// log raw payload for diagnosis, surface a friendly 'Trip.com returned no package data' message
} else {
throw err;
}
} Prevention
- Log the full upstream payload when validation fails to detect schema drift early
- Pin and update the adapter when Trip.com changes their API shape
- Treat CAPTCHA/error JSON envelopes as a distinct case from missing data
- Alert on repeated malformed-payload occurrences (likely anti-bot or schema change)
When it happens
Trigger: Calling fetchPackageSearch (via the `groups` command) when Trip.com returns JSON without `grouplist` — e.g. the API changed its response schema, returned a CAPTCHA/error JSON envelope, or an empty/error payload for the searched route/date.
Common situations: Trip.com silently changing their package-search response schema; rate-limiting or bot detection returning a JSON error object; querying obscure routes/dates where the upstream returns no group data but a valid JSON object; stale adapter code after a Trip.com site update.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Chess.com stats payload for ${kind} is not an object
- Chess.com stats payload for ${kind}.last is not an object
- Chess.com stats payload for ${kind}.best is not an object
- Chess.com stats payload for ${kind}.record is not an object
- Chess.com game archive entry is not an object
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0ce91ebf58caeaa1.
Report an issue: GitHub.