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
- Use exactly 'best-matches' or 'most-recent' (hyphenated, lowercase)
- Omit --tab to use the default 'best-matches'
- 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
- Use exact hyphenated lowercase keys from --help
- Don't copy human-readable tab labels from the web UI
- Omit --tab to accept the default
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
- upwork sort must be one of ${Array.from(SORT_VALUES).join('
- ${label} must be one of: ${Object.keys(choices).join(', ')}
- ${label} must be one of: ${choices.join(', ')}
- unsupported notification type: ${value}
- upwork ${label} must be >= ${min}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/83dd81fd2bd77be7.
Report an issue: GitHub.