{"record":{"id":"d7b93a51d6166b97","repo":"ruby/ruby","slug":"an-empty-gem-name-is-not-valid","errorCode":null,"errorMessage":"an empty gem name is not valid","messagePattern":"an empty gem name is not valid","errorType":"exception","errorClass":"GemfileError","httpStatus":null,"severity":"error","filePath":"lib/bundler/dsl.rb","lineNumber":470,"sourceCode":"    def normalize_hash(opts)\n      opts.keys.each do |k|\n        opts[k.to_s] = opts.delete(k) unless k.is_a?(String)\n      end\n      opts\n    end\n\n    def valid_keys\n      @valid_keys ||= VALID_KEYS\n    end\n\n    def normalize_options(name, version, opts)\n      if name.is_a?(Symbol)\n        raise GemfileError, %(You need to specify gem names as Strings. Use 'gem \"#{name}\"' instead)\n      end\n      if /\\s/.match?(name)\n        raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace)\n      end\n      raise GemfileError, %(an empty gem name is not valid) if name.empty?\n\n      normalize_hash(opts)\n\n      git_names = @git_sources.keys.map(&:to_s)\n      validate_keys(\"gem '#{name}'\", opts, valid_keys + git_names)\n\n      groups = @groups.dup\n      opts[\"group\"] = opts.delete(\"groups\") || opts[\"group\"]\n      groups.concat Array(opts.delete(\"group\"))\n      groups = [:default] if groups.empty?\n\n      install_if = @install_conditionals.dup\n      install_if.concat Array(opts.delete(\"install_if\"))\n      install_if = install_if.reduce(true) do |memo, val|\n        memo && (val.respond_to?(:call) ? val.call : val)\n      end\n\n      platforms = @platforms.dup","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/ruby/ruby/blob/0e5b888e1c355f3f728f2659f085820937dada48/lib/bundler/dsl.rb#L452-L488","documentation":"The third name check in normalize_options (lib/bundler/dsl.rb:470): a zero-length name is rejected immediately. Empty names almost never come from literal `gem \"\"` but from interpolation that produced nothing, so the message is the fastest way to discover that a variable feeding the Gemfile is nil or blank.","triggerScenarios":"`gem \"#{gem_name}\"` where gem_name is nil (\"#{nil}\" would give \"nil\" — but an unset hash key or empty string gives \"\"), loops like `GEMS.each { |g| gem g[:name] }` with a missing key, or ERB templates rendering an empty attribute.","commonSituations":"Templated/ERB-generated Gemfiles where a config value is missing in one environment; scripts reading a manifest that has blank lines mapped to empty strings; refactors that renamed a variable but not the symbol it reads from.","solutions":["Find the `gem` line whose interpolated variable is blank — log or print the inputs feeding the Gemfile","Default or validate the value before use: `gem gem_name.to_s.strip` after raising on blank, or `ENV.fetch(\"GEM_NAME\")` to fail with a clearer error","For generated Gemfiles, add a blank-name assertion in the generator so the error points at your data, not Bundler"],"exampleFix":"# before\nGEMS.each { |name, constraints| gem name, constraints } # name is \"\" for one row\n\n# after\nGEMS.each do |name, constraints|\n  raise ArgumentError, \"blank gem name in manifest row\" if name.to_s.strip.empty?\n  gem name, constraints\nend","handlingStrategy":"validation","validationCode":"# Fail with your own diagnostic when generated names are blank\nGEMS.each do |name, req|\n  raise ArgumentError, \"blank gem name for requirements #{req.inspect}\" if name.to_s.strip.empty?\n  gem name, req\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use Hash#fetch (not []) for manifest keys feeding gem names so missing keys raise at your call site with context","Add a blank-name assertion inside Gemfile generators so failures point at the data file and row","Log the resolved name list before evaluating a generated Gemfile"],"tags":["ruby","bundler","gemfile","validation","invalid-name","empty-string"],"backgroundTag":"invalid-package-name","analyzedSha":"0e5b888e1c355f3f728f2659f085820937dada48","analyzedAt":"2026-08-21T14:25:43.473Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}