jackwener/OpenCLI · error · ArgumentError

--${name} is too long (max 60 chars): ${JSON.stringify(raw)}

Error message

--${name} is too long (max 60 chars): ${JSON.stringify(raw)}

What it means

parseKeyword caps keyword length at 60 characters because Trip.com search endpoints reject or mis-handle longer terms. Values longer than 60 chars (after trimming) throw ArgumentError showing the full raw value. This guards both URL length and upstream API constraints.

Source

Thrown at clis/trip/utils.js:405

    };
    const found = detect();
    if (found) return resolve(found);
    const observer = new MutationObserver(() => {
      const result = detect();
      if (result) { observer.disconnect(); resolve(result); }
    });
    observer.observe(document.documentElement, { childList: true, subtree: true });
    setTimeout(() => { observer.disconnect(); resolve('timeout'); }, 12000);
  })
`;

export function parseKeyword(name, raw) {
    if (raw === undefined || raw === null || String(raw).trim() === '') {
        throw new ArgumentError(`--${name} is required (a destination or attraction keyword)`);
    }
    const value = String(raw).trim();
    if (value.length > 60) {
        throw new ArgumentError(`--${name} is too long (max 60 chars): ${JSON.stringify(raw)}`);
    }
    return value;
}

export function buildAttractionSearchUrl(keyword) {
    const params = new URLSearchParams({ keyword, locale: 'en_US', curr: 'USD' });
    return `https://www.trip.com/things-to-do/list?${params.toString()}`;
}

/**
 * Browser-context IIFE that extracts attraction / experience rows from Trip.com's
 * things-to-do results. The product cards use hashed CSS-module class names, so
 * this anchors on the one stable handle each card exposes, the
 * `things-to-do/detail/<id>` link (name is its text, `url` its href), and reads
 * rating / reviews / booked / price from the card's text by data-format pattern
 * rather than by hashed class. The price excludes the "$N off" promo tag and
 * takes the current (lowest non-promo) fare. Cards without a name or id are
 * dropped rather than surfaced with blanks.

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Shorten the keyword to the essential attraction/destination name (<=60 chars), e.g. "Tokyo Tower" instead of a full sentence
  2. Split long queries: use --city for the destination and --query for the attraction separately
  3. Trim redundant words (adjectives, marketing copy) before passing the value
  4. Check String(keyword).trim().length <= 60 in your wrapper before invoking

Example fix

// before
--query "cheapest 5 star luxury hotel near Tokyo station with breakfast spa and city view"
// after
--query "Tokyo Station"
Defensive patterns

Strategy: validation

Validate before calling

const kw = String(keyword ?? '').trim();
if (kw.length === 0) throw new Error('keyword is required');
if (kw.length > 60) throw new Error(`keyword too long (${kw.length} > 60): use a short attraction/destination name`);

Type guard

const isValidKeyword = (v) => typeof v === 'string' && v.trim().length > 0 && v.trim().length <= 60;

Try / catch

try {
  await runCli(['attractions-search', '--query', keyword]);
} catch (e) {
  if (/is too long \(max 60 chars\)/.test(e.message)) {
    keyword = String(keyword).trim().slice(0, 60);
    return runCli(['attractions-search', '--query', keyword]);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a long natural-language query like --query "best cheap family friendly hotels near the airport with free breakfast and pool view"; passing multi-word addresses or entire sentences as --city/--country; accidental duplication of a keyword string.

Common situations: Developers paste full search sentences instead of short attraction names; concatenating city + country into one flag; log or headline strings reused as keywords; localization strings longer than the limit.

Related errors


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