github-linguist/linguist · error · ArgumentError

Duplicate language name: #{language.name}

Error message

Duplicate language name: #{language.name}

What it means

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.

Source

Thrown at lib/linguist/language.rb:52

    #
    # Returns an array
    def self.by_type(type)
      all.select { |h| h.type == type }
    end

    # Internal: Create a new Language object
    #
    # attributes - A hash of attributes
    #
    # Returns a Language object
    def self.create(attributes = {})
      language = new(attributes)

      @languages << language

      # All Language names should be unique. Raise if there is a duplicate.
      if @name_index.key?(language.name)
        raise ArgumentError, "Duplicate language name: #{language.name}"
      end

      # Language name index
      @index[language.name.downcase] = @name_index[language.name.downcase] = language

      # Index filesystem name if defined
      if language.fs_name
        if @name_index.key?(language.fs_name)
          raise ArgumentError "Duplicate language name: #{language.fs_name}"
        end
        @index[language.fs_name.downcase] = @name_index[language.fs_name.downcase] = language
      end

      language.aliases.each do |name|
        # All Language aliases should be unique. Raise if there is a duplicate.
        if @alias_index.key?(name)
          raise ArgumentError, "Duplicate alias: #{name}"
        end

View on GitHub (pinned to b45dbe9b28)

Solutions

  1. Search lib/linguist/languages.yml for the exact name (case-insensitive) and rename your new entry to something genuinely unique.
  2. 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.
  3. If you intended to update an existing language, edit its existing YAML entry instead of adding a second block.
  4. If you hit this after merging upstream, diff your languages.yml against upstream and remove the duplicated block introduced by the merge.
  5. If calling Language.create directly, guard with Language.find_by_name(name).nil? first.

Example fix

# before (lib/linguist/languages.yml)
Matlab:
  type: programming

# after
MATLAB:  # existing entry, extend it instead of adding a duplicate name
  type: programming
  extensions:
    - .mat
Defensive patterns

Strategy: validation

Validate before calling

# Before adding a language / calling Language.create
name = "MyLang"
taken = Linguist::Language.all.any? do |l|
  l.name.downcase == name.downcase || l.fs_name&.downcase == name.downcase
end
raise ArgumentError, "name already registered: #{name}" if taken

Try / catch

begin
  Linguist::Language.create(attributes)
rescue ArgumentError => e
  raise if e.message !~ /Duplicate language name/
  # report the YAML entry and continue without registering
end

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of github-linguist/linguist@b45dbe9b28 (2026-08-21). Data as JSON: /api/errors/474ecb3a8f138893. Report an issue: GitHub.