jackwener/OpenCLI · error · CommandExecutionError

Trip.com poiSearch failed with status ${response.status}

Error message

Trip.com poiSearch failed with status ${response.status}

What it means

After the fetch resolves, fetchPoiSearch checks response.ok. Any non-2xx HTTP status (403 rate limit, 404, 5xx server error, 429 too many requests) is raised as CommandExecutionError with 'Trip.com poiSearch failed with status N'. This means the network round-trip succeeded but Trip.com's server rejected the request.

Source

Thrown at clis/trip/utils.js:845

 */
export async function fetchPoiSearch(keyword) {
    let response;
    try {
        response = await fetch(POI_SEARCH_ENDPOINT, {
            method: 'POST',
            headers: { 'content-type': 'application/json', currency: 'USD' },
            body: JSON.stringify({
                key: keyword,
                mode: '0',
                tripType: 'RT',
                Head: { Currency: 'USD', Locale: 'en-US', Source: 'ONLINE', Channel: 'EnglishSite', ClientID: 'opencli-trip' },
            }),
        });
    } catch (err) {
        throw new CommandExecutionError(`Trip.com poiSearch fetch failed: ${err instanceof Error ? err.message : String(err)}`);
    }
    if (!response.ok) {
        throw new CommandExecutionError(`Trip.com poiSearch failed with status ${response.status}`);
    }
    let payload;
    try {
        payload = await response.json();
    } catch (err) {
        throw new CommandExecutionError(`Trip.com poiSearch returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
    }
    if (!Array.isArray(payload?.results)) {
        throw new CommandExecutionError('Trip.com poiSearch returned malformed payload: missing results array');
    }
    return payload.results;
}

/**
 * Flatten POI results into a flat suggestion list: each top-level city keeps its
 * own row, and its `childResults` (nearby airports) follow, so a single search
 * surfaces both the city id and the airport codes.
 */

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the full status and response body (via a debug/proxy) to identify the cause
  2. Throttle requests: add delay between calls to avoid 429 rate limiting
  3. Retry with exponential backoff for transient 5xx/429 statuses
  4. Check Trip.com API availability/status; if 403 persists, the request may need updated headers/anti-bot tokens

Example fix

// before
for (const kw of keywords) await search(kw) // hammers endpoint -> 429
// after
for (const kw of keywords) { await search(kw); await sleep(1500) }
Defensive patterns

Strategy: retry

Validate before calling

// validate request shape before sending to reduce 4xx risk
if (!keyword || typeof keyword !== 'string') throw new Error('keyword required before calling poiSearch');

Type guard

null

Try / catch

async function searchWithRetry(keyword, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try { return await searchAttractions(keyword); }
    catch (e) {
      const m = /failed with status (\d+)/.exec(e.message);
      if (m && (m[1] === '429' || m[1].startsWith('5')) && i < retries - 1) { await sleep(1000 * 2 ** i); continue; }
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: Hitting the poiSearch endpoint too frequently (429); Trip.com blocking bot-like traffic (403); endpoint path changed (404); Trip.com server-side incident (500/502/503) during a request from a results-calling command.

Common situations: Loops issuing many POI searches in quick succession; expired or missing cookies/anti-bot tokens; WAF/CDN rules flagging the client; partial Trip.com outages.

Related errors


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