{"record":{"id":"2e2be4dd5f388e97","repo":"github-linguist/linguist","slug":"read-index-is-deprecated","errorCode":null,"errorMessage":"read_index is deprecated","messagePattern":"read_index is deprecated","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"warning","filePath":"lib/linguist/repository.rb","lineNumber":132,"sourceCode":"\n    # Public: Return the cached results of the analysis\n    #\n    # This is a per-file breakdown that can be passed to other instances\n    # of Linguist::Repository to perform incremental scans\n    #\n    # Returns a map of filename => [language, size]\n    def cache\n      @cache ||= begin\n        if @old_commit_oid == @commit_oid\n          @old_stats\n        else\n          compute_stats(@old_commit_oid, @old_stats)\n        end\n      end\n    end\n\n    def read_index\n      raise NotImplementedError, \"read_index is deprecated\" unless repository.is_a? Linguist::Source::RuggedRepository\n      repository.set_attribute_source(@commit_oid)\n    end\n\n    def current_tree\n      raise NotImplementedError, \"current_tree is deprecated\" unless repository.is_a? Linguist::Source::RuggedRepository\n      repository.get_tree(@commit_oid)\n    end\n\n    protected\n    def compute_stats(old_commit_oid, cache = nil)\n      return {} if repository.get_tree_size(@commit_oid, @max_tree_size) >= @max_tree_size\n\n      repository.set_attribute_source(@commit_oid)\n      diff = repository.diff(old_commit_oid, @commit_oid)\n\n      # Clear file map and fetch full diff if any .gitattributes files are changed\n      if cache && diff.each_delta.any? { |delta| File.basename(delta.new_file[:path]) == \".gitattributes\" }\n        diff = repository.diff(nil, @commit_oid)","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/github-linguist/linguist/blob/b45dbe9b2825a43285bcd035861be91cc0a7299e/lib/linguist/repository.rb#L114-L150","documentation":"read_index is a legacy helper on Linguist::Repository that only still works when the underlying source is the Rugged-backed implementation: it raises NotImplementedError ('read_index is deprecated') unless `repository.is_a?(Linguist::Source::RuggedRepository)`. The Repository constructor wraps anything that is not already a Source::Repository in a RuggedRepository for backward compatibility, so the raise specifically means a custom Source::Repository implementation was injected and the old Rugged-specific path (set_attribute_source) cannot run on it. Modern code should use the public analysis API (#language_stats / #cache) instead of this internal helper.","triggerScenarios":"1) Constructing Linguist::Repository with your own Linguist::Source::Repository implementation and then calling `repo.read_index`. 2) Old application/test code still calling read_index after upgrading to a linguist version that abstracted sources (5.x). 3) Test doubles standing in for the source, which are not RuggedRepository instances.","commonSituations":"Upgrading github-linguist in a hosting stack that now passes a non-Rugged source adapter; long-lived internal scripts that poke at repository internals; RSpec specs that build a Repository around a fake source and reuse pre-5.x helper calls.","solutions":["Replace the read_index call with the public API: `repo.language_stats` (or `repo.cache`) which works for every source implementation.","If you truly need the git-attributes side effect, call `repo.repository.set_attribute_source(repo.instance_variable_get(:@commit_oid))` only after checking the source type — or better, keep that logic inside your Rugged adapter.","If you control the call site and must keep behavior, gate it: `repo.read_index if repo.repository.is_a?(Linguist::Source::RuggedRepository)`.","Upgrade scripts/tooling that referenced this helper when you bumped the linguist gem version."],"exampleFix":"# before\nlinguist_repo.read_index\nstats = linguist_repo.language_stats\n\n# after\nstats = linguist_repo.language_stats","handlingStrategy":"type-guard","validationCode":"def rugged_backed?(linguist_repo)\n  linguist_repo.repository.is_a?(Linguist::Source::RuggedRepository)\nend\n\nlinguist_repo.read_index if rugged_backed?(linguist_repo)","typeGuard":"def supports_legacy_index?(linguist_repo)\n  linguist_repo.repository.is_a?(Linguist::Source::RuggedRepository)\nend","tryCatchPattern":"begin\n  linguist_repo.read_index\nrescue NotImplementedError => e\n  raise unless e.message =~ /read_index is deprecated/\n  # source is not Rugged-backed: rely on language_stats instead\nend","preventionTips":["Prefer the public API (#language_stats, #cache) — it works for every source implementation.","When injecting a custom Source::Repository, audit call sites for read_index/current_tree leftovers.","Treat NotImplementedError-on-deprecated-helper as an upgrade TODO, not something to rescue-and-ignore permanently."],"tags":["ruby","linguist","deprecation","not-implemented","upgrade"],"backgroundTag":"deprecated-api-called","analyzedSha":"b45dbe9b2825a43285bcd035861be91cc0a7299e","analyzedAt":"2026-08-21T15:30:05.145Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}