{"record":{"id":"15532b1869d8bf57","repo":"jackwener/OpenCLI","slug":"endoflife-product-is-required-e-g-nodejs-pyt","errorCode":null,"errorMessage":"endoflife product is required (e.g. \"nodejs\", \"python\", \"ubuntu\")","messagePattern":"endoflife product is required \\(e\\.g\\. \"nodejs\", \"python\", \"ubuntu\"\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/endoflife/utils.js","lineNumber":16,"sourceCode":"// Shared helpers for the endoflife.date adapters.\n//\n// endoflife.date publishes a free, unauthenticated REST API with cycle / EOL /\n// 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`);","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/endoflife/utils.js#L1-L34","documentation":"requireProduct normalizes and validates the endoflife product slug. If the value is empty/missing after trimming and lowercasing, it throws an ArgumentError stating a product slug is required, with a hint pointing to https://endoflife.date/<product>. This prevents issuing requests for an empty resource path.","triggerScenarios":"Calling the endoflife product CLI/command without --product, or with an empty string, whitespace-only value, null, or undefined.","commonSituations":"Forgot to pass the product argument in a script, an env variable or config key feeding the slug is unset, pipeline upstream emits an empty field.","solutions":["Pass a valid product slug, e.g. product 'nodejs' or --product python","Look up the correct slug at https://endoflife.date/<product>","Check the config/env source supplying the product name isn't empty","Pre-validate the argument in your script before invoking the CLI"],"exampleFix":"// before\nconst name = process.env.PRODUCT; // undefined\nawait product(name);\n// after\nif (!process.env.PRODUCT) throw new Error('set PRODUCT');\nawait product(process.env.PRODUCT);","handlingStrategy":"validation","validationCode":"function requireProductArg(v) {\n  const s = String(v ?? '').trim().toLowerCase();\n  if (!s) throw new Error('product slug required, e.g. nodejs, python, ubuntu');\n  return s;\n}","typeGuard":"function hasProduct(v) { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try {\n  await eolProduct(args.product);\n} catch (e) {\n  if (e instanceof ArgumentError) { console.error('usage: product <slug>'); process.exitCode = 2; }\n  else throw e;\n}","preventionTips":["Always pass --product explicitly when scripting","Check that env/config supplying the slug is non-empty before invoking","Validate args at script entry with an early guard","Include example slugs in your wrapper's usage text"],"tags":["validation","argument","missing-argument","endoflife"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}