jackwener/OpenCLI · error · ArgumentError

packagist package "${value}" must be "<vendor>/<package>"

Error message

packagist package "${value}" must be "<vendor>/<package>"

What it means

requirePackageName throws this ArgumentError when the input is non-empty but not shaped like a Composer name: there is no '/', or the '/' is the first or last character (slash <= 0 || slash === raw.length - 1). Both `<vendor>` and `<package>` segments are required by Composer convention. The offending value is echoed in the message.

Source

Thrown at clis/packagist/utils.js:38

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(`packagist ${label} must be a positive integer`);
    }
    if (n > maxValue) {
        throw new ArgumentError(`packagist ${label} must be <= ${maxValue}`);
    }
    return n;
}

export function requirePackageName(value) {
    const raw = String(value ?? '').trim().toLowerCase();
    if (!raw) {
        throw new ArgumentError('packagist package name is required (e.g. "symfony/console", "monolog/monolog")');
    }
    const slash = raw.indexOf('/');
    if (slash <= 0 || slash === raw.length - 1) {
        throw new ArgumentError(
            `packagist package "${value}" must be "<vendor>/<package>"`,
            'Both segments are required (Composer convention).',
        );
    }
    const vendor = raw.slice(0, slash);
    const pkg = raw.slice(slash + 1);
    if (vendor.length > 100 || pkg.length > 100 || !SEGMENT.test(vendor) || !SEGMENT.test(pkg)) {
        throw new ArgumentError(
            `packagist package "${value}" is not a valid Composer name`,
            'Use lowercase letters / digits / "_-.", segments separated by single "_-." chars (max 100 chars each).',
        );
    }
    return { vendor, package: pkg, full: `${vendor}/${pkg}` };
}

export async function packagistFetch(url, label) {
    let resp;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use the full vendor/package form, e.g. "monolog/monolog" instead of "monolog".
  2. Strip surrounding slashes from copied URL fragments before calling.
  3. If you only have a package name, resolve the vendor first (e.g. via search) then call full.
  4. Catch ArgumentError and hint the user with the `<vendor>/<package>` format.

Example fix

// before
await full('symfony'); // no vendor segment

// after
await full('symfony/console');
Defensive patterns

Strategy: validation

Validate before calling

function isVendorPackage(v) {
  if (typeof v !== 'string') return false;
  const s = v.trim().toLowerCase();
  const i = s.indexOf('/');
  return i > 0 && i < s.length - 1;
}
if (!isVendorPackage(name)) throw new Error(`'${name}' must be <vendor>/<package>`);

Type guard

const hasBothSegments = (v) => {
  const s = String(v ?? '').trim();
  const i = s.indexOf('/');
  return i > 0 && i < s.length - 1;
};

Try / catch

try {
  await full(name);
} catch (e) {
  if (e instanceof ArgumentError && /<vendor>\/<package>/.test(e.message)) {
    console.error(`'${name}' is not <vendor>/<package>. Try 'packagist search ${name}'.`);
    process.exitCode = 2;
  } else throw e;
}

Prevention

When it happens

Trigger: Calling full with 'symfony' (no slash), '/console' (leading slash), 'symfony/' (trailing slash), or 'a/b/c' still passes this check (first slash used) — the failing cases are missing or edge-position slashes.

Common situations: User types just the package name 'monolog' out of npm habit; copying a URL fragment like '/packages/monolog/monolog' leaves stray slashes; autocomplete produced a trailing slash.

Related errors


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