jackwener/OpenCLI · error · ArgumentError

upwork sort must be one of ${Array.from(SORT_VALUES).join('

Error message

upwork sort must be one of ${Array.from(SORT_VALUES).join(' / ')}, got "${value}"

What it means

requireSort validates the sort option against SORT_VALUES = {recency, relevance, client_total_charge, client_total_reviews}. Any other value throws ArgumentError listing the allowed sort keys.

Source

Thrown at clis/upwork/utils.js:99

    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();
    params.set('q', query);
    if (location) params.set('location', location);
    if (category) params.set('category2_uid', category);
    if (sort && sort !== 'recency') params.set('sort', sort);
    if (perPage && perPage !== 10) params.set('per_page', String(perPage));
    if (page && page > 1) params.set('page', String(page));
    return `${UPWORK_ORIGIN}/nx/search/jobs/?${params.toString()}`;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use one of: recency, relevance, client_total_charge, client_total_reviews
  2. Omit --sort to use the default 'recency'
  3. Check --help output for the current list of supported sort values

Example fix

// before
$ opencli upwork search "vue" --sort clientTotalCharge
// after
$ opencli upwork search "vue" --sort client_total_charge
Defensive patterns

Strategy: validation

Validate before calling

const SORTS = ['recency','relevance','client_total_charge','client_total_reviews'];
function isValidSort(s) {
  return SORTS.includes(String(s ?? '').trim().toLowerCase());
}

Type guard

function isSortValue(v) {
  return ['recency','relevance','client_total_charge','client_total_reviews'].includes(v);
}

Try / catch

try {
  await search({ q, sort });
} catch (e) {
  if (e instanceof ArgumentError && /sort must be one of/.test(e.message)) {
    return search({ q, sort: 'recency' });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a search/feed command with --sort set to an unsupported key like 'date', 'rating', or 'client_hire_rate'; typo in one of the snake_case keys (e.g. 'client total charges').

Common situations: Using sort names from the Upwork web UI's dropdown which don't match the API keys; assuming camelCase ('clientTotalCharge') works; stale scripts referencing a sort key that was removed or renamed.

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/79c991373bc7f6e5. Report an issue: GitHub.