jackwener/OpenCLI · error · ArgumentError

upwork tab must be one of ${Object.keys(FEED_TABS).join(' /

Error message

upwork tab must be one of ${Object.keys(FEED_TABS).join(' / ')}, got "${value}"

What it means

requireFeedTab validates the feed tab option against the FEED_TABS map, which contains only 'best-matches' and 'most-recent'. Unknown values (after trim/lowercase) throw ArgumentError listing the valid keys.

Source

Thrown at clis/upwork/utils.js:91

 * Upwork job ids are the ciphertext form starting with `~01` or `~02`
 * (the encoded uid surfaced everywhere in URLs and search results).
 * Accepts a bare ciphertext or a full `/jobs/~02…` URL.
 */
export function requireCiphertext(value) {
    let id = String(value ?? '').trim();
    if (!id) throw new ArgumentError('upwork job id is required');
    const urlMatch = id.match(/~0[12]\d+/);
    if (urlMatch) id = urlMatch[0];
    if (!CIPHERTEXT_PATTERN.test(id)) {
        throw new ArgumentError(`upwork job id "${value}" is not a valid ciphertext (expected ~01… or ~02… followed by digits)`);
    }
    return id;
}

export function requireFeedTab(value, defaultValue = 'best-matches') {
    const v = String(value ?? defaultValue).trim().toLowerCase();
    if (!FEED_TABS[v]) {
        throw new ArgumentError(`upwork tab must be one of ${Object.keys(FEED_TABS).join(' / ')}, got "${value}"`);
    }
    return v;
}

export function requireSort(value, defaultValue = 'recency') {
    const v = String(value ?? defaultValue).trim().toLowerCase();
    if (!SORT_VALUES.has(v)) {
        throw new ArgumentError(`upwork sort must be one of ${Array.from(SORT_VALUES).join(' / ')}, got "${value}"`);
    }
    return v;
}

/**
 * Build the Upwork search URL. Only forwards filters the user actually
 * supplied so the URL stays canonical and round-trippable.
 */
export function buildSearchUrl({ query, location, category, sort, page, perPage }) {
    const params = new URLSearchParams();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use exactly 'best-matches' or 'most-recent' (hyphenated, lowercase)
  2. Omit --tab to use the default 'best-matches'
  3. Run the command's --help to see the enumerated tab values

Example fix

// before
$ opencli upwork feed --tab "Best Matches"
// after
$ opencli upwork feed --tab best-matches
Defensive patterns

Strategy: validation

Validate before calling

const FEED_TABS = ['best-matches', 'most-recent'];
function isValidTab(t) {
  return FEED_TABS.includes(String(t ?? '').trim().toLowerCase());
}

Type guard

function isFeedTab(v) {
  return v === 'best-matches' || v === 'most-recent';
}

Try / catch

try {
  await feed({ tab });
} catch (e) {
  if (e instanceof ArgumentError && /tab must be one of/.test(e.message)) {
    return feed({ tab: 'best-matches' });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the feed command with --tab set to anything other than best-matches/most-recent, e.g. 'saved-jobs', 'Best Matches' with a space, or a typo like 'bestmatch'.

Common situations: Guessing tab names instead of checking help output; copying tab labels from the Upwork web UI which differ from the CLI keys; casing/space variants that the trim().toLowerCase() normalization doesn't fix (e.g. internal spaces).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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