jackwener/OpenCLI · error · CommandExecutionError

Trip.com package search returned invalid JSON: ${err instanc

Error message

Trip.com package search returned invalid JSON: ${err instanceof Error ? err.message : String(err)}

What it means

fetchPackageSearch calls response.json() and re-throws parse failures as CommandExecutionError with 'Trip.com package search returned invalid JSON: ...'. The HTTP response was received (status checked) but the body is not valid JSON — typically an HTML page, an empty body, or a truncated stream.

Source

Thrown at clis/trip/utils.js:964

    };
    let response;
    try {
        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] || {};

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Fetch the endpoint with curl to see the raw body and confirm what is returned
  2. Look for anti-bot/challenge HTML — switch headers, add cookies, or change egress IP
  3. Retry to rule out transient truncation
  4. Route through a debug proxy to capture the exact bytes and headers received

Example fix

// before
const groups = await fetchPackageSearch(body) // HTML body -> JSON.parse throws
// after
try { const groups = await fetchPackageSearch(body) }
catch (e) { if (String(e.message).includes('invalid JSON')) log('got non-JSON body, likely anti-bot page'); throw e }
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

function hasGroupList(payload) {
  return payload !== null && typeof payload === 'object' && Array.isArray(payload.grouplist);
}

Try / catch

try {
  const groups = await searchPackages(params);
} catch (e) {
  if (/package search returned invalid JSON/.test(e.message)) {
    console.error('Non-JSON body from package search — check for anti-bot HTML or proxy injection.');
    return retryAfterDelay(() => searchPackages(params), 5000);
  }
  throw e;
}

Prevention

When it happens

Trigger: Trip.com serving an HTML anti-bot/challenge page with 200 status; response body truncated mid-transfer; empty body on unusual statuses; proxy injecting HTML error pages into the response stream.

Common situations: Anti-bot interstitials on datacenter IPs; corporate proxies replacing error responses with HTML; unstable connections truncating large package-search payloads; CDN caching anomalous responses.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/ed8bfc0df39d3e16. Report an issue: GitHub.