{"record":{"id":"6dea07a3466bcbfd","repo":"github-linguist/linguist","slug":"duplicate-language-name-language-fs-name","errorCode":null,"errorMessage":"Duplicate language name: #{language.fs_name}","messagePattern":"Duplicate language name: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/linguist/language.rb","lineNumber":61,"sourceCode":"    #\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\n\n        @index[name.downcase] = @alias_index[name.downcase] = language\n      end\n\n      language.extensions.each do |extension|\n        if extension !~ /^\\./\n          raise ArgumentError, \"Extension is missing a '.': #{extension.inspect}\"\n        end\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/github-linguist/linguist/blob/b45dbe9b2825a43285bcd035861be91cc0a7299e/lib/linguist/language.rb#L43-L79","documentation":"Language.create also indexes each language's optional filesystem name (fs_name) into the same @name_index used for names, and rejects a duplicate. Note a latent bug in the raise itself: the line is `raise ArgumentError \"Duplicate language name: ...\"` — missing the comma between the exception class and the message. Ruby parses this as a call to an undefined method `ArgumentError(msg)`, so when this branch fires you actually get a NameError ('undefined method `ArgumentError`'), not the intended ArgumentError. The intended meaning is that two languages claim the same on-disk name.","triggerScenarios":"1) Two entries in languages.yml declaring the same fs_name (e.g. both `fs_name: C`). 2) A language whose fs_name collides with another language's downcased name (both live in @name_index; the check compares fs_name against downcased stored keys). 3) Calling Linguist::Language.create with a fs_name already registered. When it fires, the visible failure is NameError from the malformed raise at language.rb:61.","commonSituations":"Adding a new language that reuses a filesystem name like 'C' or 'Shell' already claimed by an adjacent language; copy-pasting a languages.yml entry and editing the name but forgetting to change fs_name; maintaining a fork with custom languages that collide with names added upstream.","solutions":["Grep languages.yml for the colliding fs_name value and remove or rename it on your new entry (fs_name is optional).","If the collision is with another language's name (not fs_name), pick a different fs_name; names and fs_names share one index.","If you are fixing the library itself, correct the raise to `raise ArgumentError, \"Duplicate language name: #{language.fs_name}\"` so the intended error is what users see.","If you hit a NameError mentioning `ArgumentError`, you have landed on this exact branch — resolve the fs_name duplication as above."],"exampleFix":"# before (lib/linguist/languages.yml)\nC:\n  type: programming\nMyC:\n  fs_name: C\n  type: programming\n\n# after\nC:\n  type: programming\nMyC:\n  type: programming","handlingStrategy":"validation","validationCode":"fs_name = \"C\"\ntaken = Linguist::Language.all.any? do |l|\n  l.fs_name&.downcase == fs_name.downcase || l.name.downcase == fs_name.downcase\nend\nraise ArgumentError, \"fs_name already registered: #{fs_name}\" if taken","typeGuard":null,"tryCatchPattern":"# NB: the raise at language.rb:61 is missing a comma, so this branch actually\n# throws NameError (undefined method `ArgumentError`), not ArgumentError.\nbegin\n  Linguist::Language.create(attributes)\nrescue ArgumentError, NameError => e\n  raise unless e.message.include?(\"ArgumentError\") || e.message =~ /Duplicate language name/\nend","preventionTips":["fs_name is optional — omit it unless the language needs a distinct on-disk name.","Remember names and fs_names share one index; check both when adding entries.","Watch for NameError mentioning `ArgumentError` — that is this duplicate-fs_name branch firing."],"tags":["ruby","yaml","configuration","boot","linguist","registry-conflict"],"backgroundTag":"duplicate-config-entries","analyzedSha":"b45dbe9b2825a43285bcd035861be91cc0a7299e","analyzedAt":"2026-08-21T15:30:05.145Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}