{"record":{"id":"5017b7ca12c5b86a","repo":"jackwener/OpenCLI","slug":"endoflife-product-value-is-not-a-valid-endof","errorCode":null,"errorMessage":"`endoflife product \"${value}\" is not a valid endoflife.date slug`","messagePattern":"`endoflife product \"(.+?)\" is not a valid endoflife\\.date slug`","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/endoflife/utils.js","lineNumber":22,"sourceCode":"// LTS data for hundreds of products. Docs: https://endoflife.date/docs/api/\nimport { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\n\nexport const EOL_BASE = 'https://endoflife.date/api';\nconst UA = 'opencli-endoflife-adapter (+https://github.com/jackwener/opencli)';\n\n// endoflife.date product slugs are lowercase ascii + digits + dashes / dots, up to 80 chars.\nconst PRODUCT = /^[a-z0-9][a-z0-9._-]{0,79}$/;\n\nexport function requireProduct(value) {\n    const s = String(value ?? '').trim().toLowerCase();\n    if (!s) {\n        throw new ArgumentError(\n            'endoflife product is required (e.g. \"nodejs\", \"python\", \"ubuntu\")',\n            'Use the slug visible at https://endoflife.date/<product>.',\n        );\n    }\n    if (!PRODUCT.test(s)) {\n        throw new ArgumentError(\n            `endoflife product \"${value}\" is not a valid endoflife.date slug`,\n            'Slugs are lowercase ASCII letters/digits/\"._-\", e.g. \"nodejs\", \"python\", \"ubuntu\".',\n        );\n    }\n    return s;\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(`endoflife ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`endoflife ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/endoflife/utils.js#L4-L40","documentation":"requireProduct enforces the endoflife.date slug grammar: lowercase ASCII letters/digits start, then only [a-z0-9._-], max 80 chars (regex /^[a-z0-9][a-z0-9._-]{0,79}$/). Values failing this pattern throw an ArgumentError, since such slugs cannot be valid endoflife.date products.","triggerScenarios":"Passing values with uppercase letters, spaces, slashes, non-ASCII characters, or leading punctuation — e.g. product 'Node.js' via a path containing '/nodejs', or 'my product'.","commonSituations":"Users supplying display names ('Ubuntu 22.04' with spaces) instead of slugs, camelCase input, URLs pasted wholesale, shell variables containing trailing whitespace or special chars (note: input is trimmed and lowercased first, so spaces inside still fail).","solutions":["Convert the product name to its official lowercase slug (e.g. 'Ubuntu 22.04' -> 'ubuntu', 'Node.js' -> 'nodejs')","Check the slug at https://endoflife.date/<product>","Strip illegal characters/spaces from the input before calling","Normalize casing in the calling script (the function lowercases but cannot fix embedded spaces/slashes)"],"exampleFix":"// before\nproduct('Node JS');\n// after\nproduct('nodejs');","handlingStrategy":"validation","validationCode":"const PRODUCT = /^[a-z0-9][a-z0-9._-]{0,79}$/;\nfunction validateSlug(v) {\n  const s = String(v ?? '').trim().toLowerCase();\n  if (!PRODUCT.test(s)) throw new Error(`\"${v}\" is not a valid endoflife.date slug`);\n  return s;\n}","typeGuard":"function isValidEolSlug(v) { return typeof v === 'string' && /^[a-z0-9][a-z0-9._-]{0,79}$/.test(v.trim().toLowerCase()); }","tryCatchPattern":"try {\n  await eolProduct(userInput);\n} catch (e) {\n  if (e instanceof ArgumentError && /not a valid/.test(e.message)) console.error('Use lowercase slugs like nodejs/python/ubuntu');\n  else throw e;\n}","preventionTips":["Map display names to official slugs before calling (e.g. 'Node.js' -> 'nodejs')","Normalize with trim().toLowerCase() and strip spaces/slashes first","Keep a lookup table of the products your tooling uses","Test inputs against the slug regex in unit tests"],"tags":["validation","argument","slug","endoflife"],"backgroundTag":"invalid-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}