{"record":{"id":"5a9ded88caf4ae9a","repo":"jackwener/OpenCLI","slug":"unknown-feed-tab-tab","errorCode":null,"errorMessage":"unknown feed tab \"${tab}\"","messagePattern":"unknown feed tab \"(.+?)\"","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/upwork/utils.js","lineNumber":121,"sourceCode":"\n/**\n * Build the Upwork search URL. Only forwards filters the user actually\n * supplied so the URL stays canonical and round-trippable.\n */\nexport function buildSearchUrl({ query, location, category, sort, page, perPage }) {\n    const params = new URLSearchParams();\n    params.set('q', query);\n    if (location) params.set('location', location);\n    if (category) params.set('category2_uid', category);\n    if (sort && sort !== 'recency') params.set('sort', sort);\n    if (perPage && perPage !== 10) params.set('per_page', String(perPage));\n    if (page && page > 1) params.set('page', String(page));\n    return `${UPWORK_ORIGIN}/nx/search/jobs/?${params.toString()}`;\n}\n\nexport function buildFeedUrl(tab) {\n    const t = FEED_TABS[tab];\n    if (!t) throw new ArgumentError(`unknown feed tab \"${tab}\"`);\n    return `${UPWORK_ORIGIN}${t.path}`;\n}\n\nexport function feedStateKey(tab) {\n    const t = FEED_TABS[tab];\n    if (!t) throw new ArgumentError(`unknown feed tab \"${tab}\"`);\n    return t.state;\n}\n\nexport function buildJobUrl(ciphertext) {\n    return `${UPWORK_ORIGIN}/jobs/${ciphertext}`;\n}\n\nexport function isValidCiphertext(value) {\n    return CIPHERTEXT_PATTERN.test(String(value ?? '').trim());\n}\n\n/**","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/upwork/utils.js#L103-L139","documentation":"buildFeedUrl maps a validated tab key to its path via FEED_TABS and throws ArgumentError for unknown keys. Unlike requireFeedTab, this is a low-level guard for callers that bypass option validation, so an unknown tab reaching here indicates the tab was never normalized/validated upstream.","triggerScenarios":"Calling buildFeedUrl directly with a raw/unvalidated string, or with a tab value that was lowercased differently or comes from a config file without passing through requireFeedTab first.","commonSituations":"Custom scripts importing the internal helper with user input; config-driven tabs not validated at load time; new tab keys assumed to exist but not present in FEED_TABS in this version.","solutions":["Pass the tab through requireFeedTab() before calling buildFeedUrl","Use only 'best-matches' or 'most-recent'","Upgrade the package if you expect a newer tab to exist — this version may not support it"],"exampleFix":"// before\nbuildFeedUrl(userTab); // throws for unknown tab\n// after\nbuildFeedUrl(requireFeedTab(userTab));","handlingStrategy":"validation","validationCode":"function safeBuildFeedUrl(tab) {\n  const valid = ['best-matches', 'most-recent'];\n  if (!valid.includes(tab)) return null;\n  return buildFeedUrl(tab);\n}","typeGuard":"function isKnownTab(v) {\n  return typeof v === 'string' && ['best-matches','most-recent'].includes(v);\n}","tryCatchPattern":"try {\n  return buildFeedUrl(tab);\n} catch (e) {\n  if (e instanceof ArgumentError && /unknown feed tab/.test(e.message)) {\n    return buildFeedUrl('best-matches');\n  }\n  throw e;\n}","preventionTips":["Run user/config input through requireFeedTab before internal helpers","Validate config values at load time","Pin the package version and match scripts to its tab set"],"tags":["validation","upwork","internal-api","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}