puppetlabs/puppet · error · ArgumentError

Invalid 'version_range' field in metadata.json: %{err}

Error message

Invalid 'version_range' field in metadata.json: %{err}

What it means

Puppet::ModuleTool::Metadata#validate_version_range wraps SemanticPuppet::VersionRange.parse and converts its ArgumentError into this metadata-specific message. Every dependency's version_requirement in metadata.json passes through here (add_dependency line 69), so one malformed range anywhere in the dependency list fails the whole metadata parse with the underlying parse error shown.

Source

Thrown at lib/puppet/module_tool/metadata.rb:224

    def validate_data_provider(value)
      if value.is_a?(String)
        unless value =~ /^[a-zA-Z][a-zA-Z0-9_]*$/
          if value =~ /^[a-zA-Z]/
            raise ArgumentError, _("field 'data_provider' contains non-alphanumeric characters")
          else
            raise ArgumentError, _("field 'data_provider' must begin with a letter")
          end
        end
      else
        raise ArgumentError, _("field 'data_provider' must be a string")
      end
    end

    # Validates that the version range can be parsed by Semantic.
    def validate_version_range(version_range)
      SemanticPuppet::VersionRange.parse(version_range)
    rescue ArgumentError => e
      raise ArgumentError, _("Invalid 'version_range' field in metadata.json: %{err}") % { err: e }
    end
  end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Use SemanticPuppet range syntax: '>= 1.0.0 < 3.0.0', '1.x', or exact '2.1.3'
  2. Remove non-SemVer conventions: no '^', no '~>', no 'latest' in version_requirement
  3. Test the range standalone: `ruby -r semantic_puppet -e "SemanticPuppet::VersionRange.parse(ARGV[0])" '>= 1.0.0 < 2.0.0'`
  4. If you want 'any version', omit version_requirement entirely instead of using a placeholder string

Example fix

// before - metadata.json
{ "name": "puppetlabs/stdlib", "version_requirement": "^4.0.0" }

// after
{ "name": "puppetlabs/stdlib", "version_requirement": ">= 4.0.0 < 5.0.0" }
Defensive patterns

Strategy: validation

Validate before calling

require 'semantic_puppet'

JSON.parse(File.read('metadata.json'))['dependencies'].each do |dep|
  next unless dep['version_requirement']
  begin
    SemanticPuppet::VersionRange.parse(dep['version_requirement'])
  rescue ArgumentError
    abort "dependency #{dep['name']} has unparseable range '#{dep['version_requirement']}'"
  end
end

Try / catch

begin
  metadata.add_dependency(dep['name'], dep['version_requirement'])
rescue ArgumentError => e
  raise unless e.message =~ /Invalid 'version_range' field/
  normalized = dep['version_requirement'].gsub(/\^|~>/, '').strip  # drop gem/npm-style operators
  metadata.add_dependency(dep['name'], normalized.empty? ? nil : normalized)
end

Prevention

When it happens

Trigger: A metadata.json dependency with "version_requirement": "latest", ">= 1.0 < < 2.0" (malformed operator), "1.x.x.x" or another string SemanticPuppet::VersionRange.parse rejects; parse error text is embedded via %{err}.

Common situations: Copy-pasting npm/gem style ranges ('^1.2.3', '~> 2.1') that SemanticPuppet does not accept; typo'd operators; empty-string requirements after bad templating; ranges assembled by string concatenation that drop a bound.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/89b22383e17a7397. Report an issue: GitHub.