ruby/ruby · error · ArgumentError
one set in the composition must be non-nil
Error message
one set in the composition must be non-nil
What it means
Gem::Resolver.compose_sets(*sets) compacts nil sets, flattens ComposedSets, and then requires at least one remaining resolver set; zero sets raises ArgumentError ('one set in the composition must be non-nil'). It is primarily an API-contract error for code driving the resolver directly - resolution needs at least one source of specifications.
Source
Thrown at lib/rubygems/resolver.rb:82
# flattened into the result ComposedSet.
def self.compose_sets(*sets)
sets.compact!
sets = sets.flat_map do |set|
case set
when Gem::Resolver::BestSet then
set
when Gem::Resolver::ComposedSet then
set.sets
else
set
end
end
case sets.length
when 0 then
raise ArgumentError, "one set in the composition must be non-nil"
when 1 then
sets.first
else
Gem::Resolver::ComposedSet.new(*sets)
end
end
##
# Creates a Resolver that queries only against the already installed gems
# for the +needed+ dependencies.
def self.for_current_gems(needed)
new needed, Gem::Resolver::CurrentSet.new
end
##
# Create Resolver object which will resolve the tree starting
# with +needed+ Dependency objects.View on GitHub (pinned to 0e5b888e1c)
Solutions
- Pass at least one concrete set, e.g. Gem::Resolver.compose_sets(Gem::Resolver::BestSet.new) or Gem::Resolver::IndexSet.new / InstalledSet.new / CurrentSet.new as appropriate
- Default nil sets to a sensible fallback before composing: sets << Gem::Resolver::BestSet.new if sets.compact.empty?
- If building from user config, validate that at least one source is enabled before constructing the resolver
Example fix
# before set = Gem::Resolver.compose_sets(maybe_set) # maybe_set is nil # after set = Gem::Resolver.compose_sets(maybe_set || Gem::Resolver::BestSet.new)
Defensive patterns
Strategy: type-guard
Validate before calling
sets = [git_set, vendor_set, index_set].compact sets = [Gem::Resolver::BestSet.new] if sets.empty? resolver_set = Gem::Resolver.compose_sets(*sets)
Type guard
def resolvable_set?(set) set.is_a?(Gem::Resolver::IndexSet) || set.is_a?(Gem::Resolver::BestSet) || set.is_a?(Gem::Resolver::ComposedSet) || set.is_a?(Gem::Resolver::InstalledSet) || set.is_a?(Gem::Resolver::CurrentSet) || set.is_a?(Gem::Resolver::VendorSet) || set.is_a?(Gem::Resolver::GitSet) || set.is_a?(Gem::Resolver::LockfileSet) || set.is_a?(Gem::Resolver::SourceSet) end
Try / catch
begin
set = Gem::Resolver.compose_sets(*sets)
rescue ArgumentError => e
raise if !e.message.include?('non-nil')
set = Gem::Resolver.compose_sets(Gem::Resolver::BestSet.new)
end Prevention
- Default optional sets to Gem::Resolver::BestSet.new before composing
- Validate resolver configuration contains at least one enabled source before resolving
- Never pass raw user-config arrays into compose_sets without compaction and an empty check
When it happens
Trigger: Gem::Resolver.compose_sets(nil), compose_sets() with no args, or compose_sets(*array) where array contains only nils; also higher-level tooling that builds sets from optional inputs (e.g. all sources disabled) and forwards an empty list to the Resolver.
Common situations: Custom installers/dependency tooling over RubyGems internals; configurations where every source is disabled (all `gem sources` removed and no local sets supplied); guard-of-absent-arguments refactors that pass nil instead of a default set.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- must be a Gem::AvailableSet
- #{spec.full_name} requires Ruby version #{rrv}. The current
- #{spec.full_name} requires RubyGems version #{rrgv}. The cur
- unable to find #{gemspec} for gem #{name}
- missing codepage argument
AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21).
Data as JSON: /api/errors/18d19c66841e59da.
Report an issue: GitHub.