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}"
endView on GitHub (pinned to b45dbe9b28)
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.
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
- 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.
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
- Duplicate language name: #{language.fs_name}
- Duplicate alias: #{name}
- Extension is missing a '.': #{extension.inspect}
- invalid type: #{@type}
- read_index is deprecated
AI-assisted analysis of github-linguist/linguist@b45dbe9b28 (2026-08-21).
Data as JSON: /api/errors/474ecb3a8f138893.
Report an issue: GitHub.