jackwener/OpenCLI · error · ArgumentError

rubygems gem "${value}" is not a valid gem name

Error message

rubygems gem "${value}" is not a valid gem name

What it means

requireGemName validates the gem name against the GEM_NAME regex /^[A-Za-z0-9][A-Za-z0-9._-]*$/ and a 100-character limit. A non-empty name that fails these checks throws ArgumentError(`rubygems gem "${value}" is not a valid gem name`) with a hint about allowed characters. This prevents sending names that can never match a real gem to rubygems.org.

Source

Thrown at clis/rubygems/utils.js:39

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

export function requireGemName(value) {
    const s = String(value ?? '').trim();
    if (!s) {
        throw new ArgumentError('rubygems gem name is required (e.g. "rails", "sidekiq")');
    }
    if (s.length > 100 || !GEM_NAME.test(s)) {
        throw new ArgumentError(
            `rubygems gem "${value}" is not a valid gem name`,
            'Use letters / digits / "._-", starting with a letter or digit (max 100 chars).',
        );
    }
    return s;
}

export async function gemsFetch(url, label) {
    let resp;
    try {
        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
    }
    catch (err) {
        throw new CommandExecutionError(
            `${label} request failed: ${err?.message ?? err}`,
            'Check that rubygems.org is reachable from this network.',
        );
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use the bare gem name only: `opencli rubygems info rails` (no URL, no version, no quotes).
  2. Strip prefixes: `basename` a URL or cut after 'gems/' before passing the value.
  3. Sanitize in code: `const name = raw.replace(/[^A-Za-z0-9._-]/g, '')` then re-check it is non-empty before calling.

Example fix

// before
await info({ name: 'https://rubygems.org/gems/rails' }); // throws

// after
const url = 'https://rubygems.org/gems/rails';
await info({ name: url.split('/gems/')[1] }); // 'rails'
Defensive patterns

Strategy: validation

Validate before calling

const GEM_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
function validGemName(v) {
  const s = String(v ?? '').trim();
  return s.length > 0 && s.length <= 100 && GEM_NAME.test(s);
}

Type guard

function isGemName(v) {
  return typeof v === 'string' && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(v) && v.length <= 100;
}

Try / catch

try {
  await info({ name });
} catch (e) {
  if (e instanceof ArgumentError && /not a valid gem name/.test(e.message)) {
    console.error('Pass the bare gem name (letters/digits/._-, max 100 chars).');
  } else throw e;
}

Prevention

When it happens

Trigger: requireGemName receives a value that is non-empty but contains characters outside [A-Za-z0-9._-], starts with '.', '_' or '-', includes spaces, slashes, or is longer than 100 chars.

Common situations: Pasting a full gem URL ('https://rubygems.org/gems/rails') or 'gem rails' instead of the bare name; including a version spec ('rails>=7'); stray quotes or whitespace inside the token; typos like './mygem'.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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