jackwener/OpenCLI · error · ArgumentError

`endoflife product "${value}" is not a valid endoflife.date

Error message

`endoflife product "${value}" is not a valid endoflife.date slug`

What it means

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.

Source

Thrown at clis/endoflife/utils.js:22

// LTS data for hundreds of products. Docs: https://endoflife.date/docs/api/
import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';

export const EOL_BASE = 'https://endoflife.date/api';
const UA = 'opencli-endoflife-adapter (+https://github.com/jackwener/opencli)';

// endoflife.date product slugs are lowercase ascii + digits + dashes / dots, up to 80 chars.
const PRODUCT = /^[a-z0-9][a-z0-9._-]{0,79}$/;

export function requireProduct(value) {
    const s = String(value ?? '').trim().toLowerCase();
    if (!s) {
        throw new ArgumentError(
            'endoflife product is required (e.g. "nodejs", "python", "ubuntu")',
            'Use the slug visible at https://endoflife.date/<product>.',
        );
    }
    if (!PRODUCT.test(s)) {
        throw new ArgumentError(
            `endoflife product "${value}" is not a valid endoflife.date slug`,
            'Slugs are lowercase ASCII letters/digits/"._-", e.g. "nodejs", "python", "ubuntu".',
        );
    }
    return s;
}

export function requireBoundedInt(value, defaultValue, maxValue, label = 'limit') {
    const raw = value ?? defaultValue;
    const n = typeof raw === 'number' ? raw : Number(raw);
    if (!Number.isInteger(n) || n <= 0) {
        throw new ArgumentError(`endoflife ${label} must be a positive integer`);
    }
    if (n > maxValue) {
        throw new ArgumentError(`endoflife ${label} must be <= ${maxValue}`);
    }
    return n;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Convert the product name to its official lowercase slug (e.g. 'Ubuntu 22.04' -> 'ubuntu', 'Node.js' -> 'nodejs')
  2. Check the slug at https://endoflife.date/<product>
  3. Strip illegal characters/spaces from the input before calling
  4. Normalize casing in the calling script (the function lowercases but cannot fix embedded spaces/slashes)

Example fix

// before
product('Node JS');
// after
product('nodejs');
Defensive patterns

Strategy: validation

Validate before calling

const PRODUCT = /^[a-z0-9][a-z0-9._-]{0,79}$/;
function validateSlug(v) {
  const s = String(v ?? '').trim().toLowerCase();
  if (!PRODUCT.test(s)) throw new Error(`"${v}" is not a valid endoflife.date slug`);
  return s;
}

Type guard

function isValidEolSlug(v) { return typeof v === 'string' && /^[a-z0-9][a-z0-9._-]{0,79}$/.test(v.trim().toLowerCase()); }

Try / catch

try {
  await eolProduct(userInput);
} catch (e) {
  if (e instanceof ArgumentError && /not a valid/.test(e.message)) console.error('Use lowercase slugs like nodejs/python/ubuntu');
  else throw e;
}

Prevention

When it happens

Trigger: 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'.

Common situations: 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).

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/5017b7ca12c5b86a. Report an issue: GitHub.