{"record":{"id":"6ca0a31b2314e801","repo":"puppetlabs/puppet","slug":"version-is-not-a-valid-ruby-gem-version","errorCode":null,"errorMessage":"#{version} is not a valid ruby gem version.","messagePattern":"#(.+?) is not a valid ruby gem version\\.","errorType":"validation","errorClass":"ValidationFailure","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/package/version/gem.rb","lineNumber":6,"sourceCode":"# frozen_string_literal: true\n\nmodule Puppet::Util::Package::Version\n  class Gem < ::Gem::Version\n    def self.parse(version)\n      raise ValidationFailure, version unless version.is_a? String\n      raise ValidationFailure, version unless version =~ ANCHORED_VERSION_PATTERN\n\n      new(version)\n    end\n\n    class ValidationFailure < ArgumentError\n      def initialize(version)\n        super(\"#{version} is not a valid ruby gem version.\")\n      end\n    end\n  end\nend\n","sourceCodeStart":1,"sourceCodeEnd":19,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/package/version/gem.rb#L1-L19","documentation":"First guard in Puppet::Util::Package::Version::Gem.parse: it raises ValidationFailure with the generic message '#{version} is not a valid ruby gem version.' when the argument is not a String (version.is_a? String check at gem.rb:6). Note the class subclasses ::Gem::Version, but unlike Gem::Version.new it refuses non-String input outright instead of coercing or raising Gem::InvalidVersionError.","triggerScenarios":"Gem.parse(nil), Gem.parse(:'1.0.0') (symbol from a Puppet manifest value), Gem.parse(1.0) or Gem.parse(2) (numeric from JSON), Gem.parse(Gem::Version.new('1.0')) (double-parsing an already parsed version object).","commonSituations":"Version values coming from YAML/JSON/Hiera that deserialize as numbers or symbols; helper code that stores parsed versions and later re-parses them; defaults of nil passed through when a key is absent.","solutions":["Coerce before parsing: pass version.to_s if the value may be a Symbol or Integer.","Guard with a type check: only call parse when value.is_a?(String).","Pre-validate with Gem::Version.correct?(value.to_s) and only construct when true.","Rescue Puppet::Util::Package::Version::Gem::ValidationFailure (ArgumentError subclass) around the call."],"exampleFix":"// before\nv = Puppet::Util::Package::Version::Gem.parse(manifest_value) # manifest_value = :'2.1.0'\n\n// after\nv = if manifest_value.is_a?(String)\n      Puppet::Util::Package::Version::Gem.parse(manifest_value)\n    elsif Gem::Version.correct?(manifest_value.to_s)\n      Puppet::Util::Package::Version::Gem.parse(manifest_value.to_s)\n    end","handlingStrategy":"type-guard","validationCode":"raw = candidate.is_a?(String) ? candidate : candidate.to_s\nok = Gem::Version.correct?(raw)","typeGuard":"def gem_version_input?(value)\n  value.is_a?(String) && Gem::Version.correct?(value)\nend","tryCatchPattern":"begin\n  Puppet::Util::Package::Version::Gem.parse(raw)\nrescue Puppet::Util::Package::Version::Gem::ValidationFailure\n  nil # treat as unparseable, keep manifest version as plain string\nend","preventionTips":["Coerce symbols/integers with to_s at the data boundary before version handling.","Never re-parse a value that is already a version object; check is_a?(Gem::Version) first.","Default manifest parameters to a sentinel like 'installed' and branch before parsing."],"tags":["rubygems","puppet","package-version","type-error","validation"],"backgroundTag":"version-string-validation","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}