{"record":{"id":"9cee36ad188e2184","repo":"jackwener/OpenCLI","slug":"upwork-job-id-value-is-not-a-valid-ciphertext","errorCode":null,"errorMessage":"upwork job id \"${value}\" is not a valid ciphertext (expected ~01… or ~02… followed by digits)","messagePattern":"upwork job id \"(.+?)\" is not a valid ciphertext \\(expected ~01… or ~02… followed by digits\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/upwork/utils.js","lineNumber":83,"sourceCode":"export function requireBoundedInt(value, defaultValue, min, max, label) {\n    const n = requirePositiveInt(value, defaultValue, label);\n    if (n < min) throw new ArgumentError(`upwork ${label} must be >= ${min}`);\n    if (n > max) throw new ArgumentError(`upwork ${label} must be <= ${max}`);\n    return n;\n}\n\n/**\n * Upwork job ids are the ciphertext form starting with `~01` or `~02`\n * (the encoded uid surfaced everywhere in URLs and search results).\n * Accepts a bare ciphertext or a full `/jobs/~02…` URL.\n */\nexport function requireCiphertext(value) {\n    let id = String(value ?? '').trim();\n    if (!id) throw new ArgumentError('upwork job id is required');\n    const urlMatch = id.match(/~0[12]\\d+/);\n    if (urlMatch) id = urlMatch[0];\n    if (!CIPHERTEXT_PATTERN.test(id)) {\n        throw new ArgumentError(`upwork job id \"${value}\" is not a valid ciphertext (expected ~01… or ~02… followed by digits)`);\n    }\n    return id;\n}\n\nexport function requireFeedTab(value, defaultValue = 'best-matches') {\n    const v = String(value ?? defaultValue).trim().toLowerCase();\n    if (!FEED_TABS[v]) {\n        throw new ArgumentError(`upwork tab must be one of ${Object.keys(FEED_TABS).join(' / ')}, got \"${value}\"`);\n    }\n    return v;\n}\n\nexport function requireSort(value, defaultValue = 'recency') {\n    const v = String(value ?? defaultValue).trim().toLowerCase();\n    if (!SORT_VALUES.has(v)) {\n        throw new ArgumentError(`upwork sort must be one of ${Array.from(SORT_VALUES).join(' / ')}, got \"${value}\"`);\n    }\n    return v;","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/upwork/utils.js#L65-L101","documentation":"requireCiphertext throws this when the provided id (after trimming and extracting a ~0[12]\\d+ substring from a possible full URL) does not match CIPHERTEXT_PATTERN /^~0[12]\\d{15,21}$/ — i.e. it is not a valid ~01/~02 ciphertext of 16-22 total characters.","triggerScenarios":"Passing a numeric Upwork uid instead of the ciphertext form; passing a truncated or corrupted id (too few digits); passing a URL whose id does not match the pattern; passing an opaque job reference from an old export.","commonSituations":"Using the internal numeric job id from the API instead of the ciphertext from URLs/search results; copy-paste truncation dropping the `~` or digits; older tooling that stored a different id format.","solutions":["Copy the full ciphertext id starting with ~01 or ~02 from the job URL or search output","If you have a job URL, pass the whole URL — the helper extracts the ciphertext automatically","Check for truncation (needs ~ + '0' + '1'/'2' + 15-21 digits)","Re-run the search/list command to obtain a fresh round-trippable id"],"exampleFix":"// before\nawait show('17483920'); // numeric uid -> not valid ciphertext\n// after\nawait show('~01a8f3c2d94b7e610253');","handlingStrategy":"validation","validationCode":"const CIPHERTEXT = /^~0[12]\\d{15,21}$/;\nfunction looksLikeCiphertext(v) {\n  if (typeof v !== 'string') return false;\n  const m = v.match(/~0[12]\\d+/);\n  return !!m && CIPHERTEXT.test(m[0]);\n}\nif (!looksLikeCiphertext(id)) throw new Error('not a ~01/~02 ciphertext id');","typeGuard":"function isJobCiphertext(v) {\n  return typeof v === 'string' && /^~0[12]\\d{15,21}$/.test(v.trim().match(/~0[12]\\d+/)?.[0] ?? '');\n}","tryCatchPattern":"try {\n  await show(id);\n} catch (e) {\n  if (e instanceof ArgumentError && /not a valid ciphertext/.test(e.message)) {\n    console.error('Use the ~01…/~02… id from a job URL or list output');\n    return null;\n  }\n  throw e;\n}","preventionTips":["Always copy ids from job URLs or list rows, never numeric uids","Pass the full /jobs/~02… URL — the helper extracts the id","Watch for shell/trailing-whitespace truncation when pasting"],"tags":["validation","format","upwork","argument-error"],"backgroundTag":"invalid-identifier-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}