{"record":{"id":"f41e23eff7002f54","repo":"jackwener/OpenCLI","slug":"rubygems-gem-value-is-not-a-valid-gem-name","errorCode":null,"errorMessage":"rubygems gem \"${value}\" is not a valid gem name","messagePattern":"rubygems gem \"(.+?)\" is not a valid gem name","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/rubygems/utils.js","lineNumber":39,"sourceCode":"export 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(`rubygems ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`rubygems ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport function requireGemName(value) {\n    const s = String(value ?? '').trim();\n    if (!s) {\n        throw new ArgumentError('rubygems gem name is required (e.g. \"rails\", \"sidekiq\")');\n    }\n    if (s.length > 100 || !GEM_NAME.test(s)) {\n        throw new ArgumentError(\n            `rubygems gem \"${value}\" is not a valid gem name`,\n            'Use letters / digits / \"._-\", starting with a letter or digit (max 100 chars).',\n        );\n    }\n    return s;\n}\n\nexport async function gemsFetch(url, label) {\n    let resp;\n    try {\n        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });\n    }\n    catch (err) {\n        throw new CommandExecutionError(\n            `${label} request failed: ${err?.message ?? err}`,\n            'Check that rubygems.org is reachable from this network.',\n        );\n    }","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rubygems/utils.js#L21-L57","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","solutions":["Use the bare gem name only: `opencli rubygems info rails` (no URL, no version, no quotes).","Strip prefixes: `basename` a URL or cut after 'gems/' before passing the value.","Sanitize in code: `const name = raw.replace(/[^A-Za-z0-9._-]/g, '')` then re-check it is non-empty before calling."],"exampleFix":"// before\nawait info({ name: 'https://rubygems.org/gems/rails' }); // throws\n\n// after\nconst url = 'https://rubygems.org/gems/rails';\nawait info({ name: url.split('/gems/')[1] }); // 'rails'","handlingStrategy":"validation","validationCode":"const GEM_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\nfunction validGemName(v) {\n  const s = String(v ?? '').trim();\n  return s.length > 0 && s.length <= 100 && GEM_NAME.test(s);\n}","typeGuard":"function isGemName(v) {\n  return typeof v === 'string' && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(v) && v.length <= 100;\n}","tryCatchPattern":"try {\n  await info({ name });\n} catch (e) {\n  if (e instanceof ArgumentError && /not a valid gem name/.test(e.message)) {\n    console.error('Pass the bare gem name (letters/digits/._-, max 100 chars).');\n  } else throw e;\n}","preventionTips":["Strip URLs and version specs down to the bare name before calling.","Reject input with spaces, slashes, or leading punctuation early.","Share a single gem-name validator across your scripts."],"tags":["validation","argument-error","rubygems","cli-input"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}