{"record":{"id":"474ecb3a8f138893","repo":"github-linguist/linguist","slug":"duplicate-language-name-language-name","errorCode":null,"errorMessage":"Duplicate language name: #{language.name}","messagePattern":"Duplicate language name: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/linguist/language.rb","lineNumber":52,"sourceCode":"    #\n    # Returns an array\n    def self.by_type(type)\n      all.select { |h| h.type == type }\n    end\n\n    # Internal: Create a new Language object\n    #\n    # attributes - A hash of attributes\n    #\n    # Returns a Language object\n    def self.create(attributes = {})\n      language = new(attributes)\n\n      @languages << language\n\n      # All Language names should be unique. Raise if there is a duplicate.\n      if @name_index.key?(language.name)\n        raise ArgumentError, \"Duplicate language name: #{language.name}\"\n      end\n\n      # Language name index\n      @index[language.name.downcase] = @name_index[language.name.downcase] = language\n\n      # Index filesystem name if defined\n      if language.fs_name\n        if @name_index.key?(language.fs_name)\n          raise ArgumentError \"Duplicate language name: #{language.fs_name}\"\n        end\n        @index[language.fs_name.downcase] = @name_index[language.fs_name.downcase] = language\n      end\n\n      language.aliases.each do |name|\n        # All Language aliases should be unique. Raise if there is a duplicate.\n        if @alias_index.key?(name)\n          raise ArgumentError, \"Duplicate alias: #{name}\"\n        end","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/github-linguist/linguist/blob/b45dbe9b2825a43285bcd035861be91cc0a7299e/lib/linguist/language.rb#L34-L70","documentation":"Language.create registers every language from lib/linguist/languages.yml into a global name index at require time, and rejects a name that is already indexed. The index keys are stored downcased and are shared between `name` and `fs_name`, so this fires when a new language's name matches an existing language's name (case-insensitively, e.g. \"ruby\" after \"Ruby\") or another language's fs_name. Because all languages are loaded when 'linguist' is required, this ArgumentError aborts the entire gem load for the process. It is a data-integrity guard: GitHub's language registry requires unique names for lookup by name to work.","triggerScenarios":"1) Adding a top-level key to lib/linguist/languages.yml whose name differs only in case from an existing language (stored keys are lowercase, so `@name_index.key?(language.name)` only matches when the new name equals an already-stored downcased key). 2) Adding a language whose name equals another language's fs_name (both write into @name_index). 3) Calling Linguist::Language.create(name: 'Ruby', ...) a second time in code or tests. 4) Hand-editing the generated languages_data.rb with a repeated entry. Exact same-case duplicates usually surface later as 'Duplicate alias' instead, because the name check uses the raw casing while keys are stored downcased.","commonSituations":"Contributing a new language to Linguist and unknowingly reusing an existing name (e.g. adding \"Matlab\" when \"MATLAB\" exists); merging upstream languages.yml changes and keeping a local fork entry with the same name; vendoring linguist with a customized languages.yml that drifts out of sync; programmatic Language.create in specs without resetting the class-level indexes.","solutions":["Search lib/linguist/languages.yml for the exact name (case-insensitive) and rename your new entry to something genuinely unique.","If the collision is with another language's fs_name rather than a name, either drop your fs_name or change it; both share the same index.","If you intended to update an existing language, edit its existing YAML entry instead of adding a second block.","If you hit this after merging upstream, diff your languages.yml against upstream and remove the duplicated block introduced by the merge.","If calling Language.create directly, guard with Language.find_by_name(name).nil? first."],"exampleFix":"# before (lib/linguist/languages.yml)\nMatlab:\n  type: programming\n\n# after\nMATLAB:  # existing entry, extend it instead of adding a duplicate name\n  type: programming\n  extensions:\n    - .mat","handlingStrategy":"validation","validationCode":"# Before adding a language / calling Language.create\nname = \"MyLang\"\ntaken = Linguist::Language.all.any? do |l|\n  l.name.downcase == name.downcase || l.fs_name&.downcase == name.downcase\nend\nraise ArgumentError, \"name already registered: #{name}\" if taken","typeGuard":null,"tryCatchPattern":"begin\n  Linguist::Language.create(attributes)\nrescue ArgumentError => e\n  raise if e.message !~ /Duplicate language name/\n  # report the YAML entry and continue without registering\nend","preventionTips":["Grep languages.yml case-insensitively for the intended name before adding an entry.","Never hand-edit the generated languages_data.rb; edit languages.yml and regenerate.","Run `bundle exec rake test` after any languages.yml change — boot-time raises surface immediately.","In programmatic specs, avoid re-creating static languages; look them up with Language.find_by_name instead."],"tags":["ruby","yaml","configuration","boot","linguist"],"backgroundTag":"duplicate-config-entries","analyzedSha":"b45dbe9b2825a43285bcd035861be91cc0a7299e","analyzedAt":"2026-08-21T15:30:05.145Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}