{"record":{"id":"a135261eee8b73b0","repo":"jackwener/OpenCLI","slug":"steam-currency-must-be-a-two-letter-storefront-cou","errorCode":null,"errorMessage":"steam currency must be a two-letter storefront country code (got \"${value}\")","messagePattern":"steam currency must be a two-letter storefront country code \\(got \"(.+?)\"\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/steam/utils.js","lineNumber":20,"sourceCode":"// endpoints (no browser).\nimport { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\n\nexport const STEAM_STORE = 'https://store.steampowered.com';\nconst UA = 'opencli-steam-adapter (+https://github.com/jackwener/opencli)';\n\nexport function requireString(value, label) {\n    const s = String(value ?? '').trim();\n    if (!s) {\n        throw new ArgumentError(`steam ${label} cannot be empty`);\n    }\n    return s;\n}\n\nexport function requireCountryCode(value, defaultValue = 'us') {\n    const raw = value === undefined || value === null ? defaultValue : value;\n    const code = String(raw).trim().toLowerCase();\n    if (!/^[a-z]{2}$/.test(code)) {\n        throw new ArgumentError(\n            `steam currency must be a two-letter storefront country code (got \"${value}\")`,\n            'Examples: us, cn, jp, de. This controls Steam regional pricing and availability.',\n        );\n    }\n    return code;\n}\n\nexport function requireBoundedInt(value, defaultValue, maxValue, label = 'limit') {\n    const raw = value ?? defaultValue;\n    const n = typeof raw === 'number' ? raw : Number(raw);\n    if (!Number.isInteger(n) || n <= 0) {\n        throw new ArgumentError(`steam ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`steam ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/steam/utils.js#L2-L38","documentation":"requireCountryCode validates the storefront country code controlling Steam regional pricing; it must be exactly two ASCII letters after trimming/lowercasing. Invalid codes throw ArgumentError with the offending value and examples.","triggerScenarios":"Passing full country names ('usa', 'germany'), three-letter codes ('DEU'), codes with digits or symbols ('u1'), or an empty string that bypassed the default because it was provided explicitly as ''.","commonSituations":"Users typing 'UK' (fine case-wise, but 'uk' is accepted only if Steam supports it) or 'USA'; config files storing locale strings like 'en-US'; copy-pasting currency codes (USD) instead of country codes.","solutions":["Pass a two-letter ISO 3166-1 alpha-2 code, e.g. us, cn, jp, de","Lowercase/trim inputs at the call site before passing","Replace locale strings like en-US with just the country portion (us)","Catch ArgumentError and show the examples included in the error's hint"],"exampleFix":"// before\nconst cc = args.currency; // \"USA\"\n// after\nconst cc = requireCountryCode(String(args.currency ?? 'us').slice(0, 2).toLowerCase());","handlingStrategy":"validation","validationCode":"const CC_RE = /^[a-z]{2}$/;\nif (!CC_RE.test(String(value ?? '').trim().toLowerCase())) {\n  throw new Error(`currency must be a 2-letter country code, got: ${value}`);\n}","typeGuard":"function isCountryCode(v) {\n  return typeof v === 'string' && /^[a-z]{2}$/.test(v.trim().toLowerCase());\n}","tryCatchPattern":"try {\n  await cmd({ currency: cc });\n} catch (e) {\n  if (e instanceof ArgumentError && /two-letter storefront country/.test(e.message)) {\n    console.error('Use codes like us, cn, jp, de');\n  } else throw e;\n}","preventionTips":["Normalize input with trim().toLowerCase().slice(0,2) before passing","Reject locale strings (en-US) by splitting on '-' and using the country part","Keep a whitelist of storefront codes your app supports","Document valid codes in CLI help text"],"tags":["validation","argument","steam","i18n"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}