{"record":{"id":"74ad3c48f361139c","repo":"github-linguist/linguist","slug":"extension-is-missing-a-extension-inspect","errorCode":null,"errorMessage":"Extension is missing a '.': #{extension.inspect}","messagePattern":"Extension is missing a '\\.': #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/linguist/language.rb","lineNumber":77,"sourceCode":"      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\n        @extension_index[extension.downcase] << language\n      end\n\n      language.interpreters.each do |interpreter|\n        @interpreter_index[interpreter] << language\n      end\n\n      language.filenames.each do |filename|\n        @filename_index[filename] << language\n      end\n\n      @language_id_index[language.language_id] = language\n\n      language\n    end\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/github-linguist/linguist/blob/b45dbe9b2825a43285bcd035861be91cc0a7299e/lib/linguist/language.rb#L59-L95","documentation":"While indexing a language's extensions, Language.create validates that every extension string starts with a literal dot (`extension =~ /^\\./`) before adding it to @extension_index. This enforces the registry convention that extensions include the leading separator, e.g. '.rb' not 'rb', which the detection strategies rely on when matching blob paths. Any entry in an `extensions:` list missing the dot raises ArgumentError during the require-time load of languages.yml.","triggerScenarios":"1) Writing a new entry in languages.yml as `extensions: [sc, .scala]` instead of [.sc, .scala]. 2) Programmatically calling Language.create(extensions: ['rb']). 3) A hand-edited or generated languages_data.rb containing an extension without the leading dot. The message prints the offending value via inspect, so it shows exactly which string failed.","commonSituations":"First-time contributors adding a language and listing extensions the way users type them (no dot); converting a list from another tool that strips dots; YAML quoting mistakes that turn an extension into a non-string or mangle it.","solutions":["Find the extension named in the message and prefix it with a dot in languages.yml (e.g. 'sc' -> '.sc').","Scan the whole extensions list of your new entry — the raise stops at the first bad one, others may follow.","If creating languages programmatically, normalize with `ext.start_with?('.') ? ext : \".#{ext}\"` before calling create.","Run the repo's test suite (`bundle exec rake test`) after YAML edits so this is caught before deploy."],"exampleFix":"# before (lib/linguist/languages.yml)\nScala:\n  extensions:\n    - sc\n    - .scala\n\n# after\nScala:\n  extensions:\n    - .sc\n    - .scala","handlingStrategy":"validation","validationCode":"extensions = attributes[:extensions].to_a\nbad = extensions.reject { |e| e.is_a?(String) && e.start_with?('.') }\nraise ArgumentError, \"extensions missing leading '.': #{bad.map(&:inspect).join(', ')}\" unless bad.empty?","typeGuard":"def valid_extension?(e)\n  e.is_a?(String) && e.match?(/\\A\\.[^.]*\\z/)\nend","tryCatchPattern":"begin\n  Linguist::Language.create(attributes)\nrescue ArgumentError => e\n  raise if e.message !~ /Extension is missing a '.'/\n  attributes[:extensions].map! { |e| e.start_with?('.') ? e : \".#{e}\" }\n  retry\nend","preventionTips":["Normalize extensions at the source: `list.map { |e| e.start_with?('.') ? e : \".#{e}\" }`.","The message prints the offending value via inspect — fix that exact string, then re-run to catch any others.","Add a lint step for languages.yml edits (the repo's test suite exercises the load path)."],"tags":["ruby","yaml","configuration","validation","linguist"],"backgroundTag":"config-validation-failed","analyzedSha":"b45dbe9b2825a43285bcd035861be91cc0a7299e","analyzedAt":"2026-08-21T15:30:05.145Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}