github-linguist/linguist · error · TypeError

commit_oid must be a commit SHA1

Error message

commit_oid must be a commit SHA1

What it means

Linguist::Repository#initialize expects commit_oid to be a plain Ruby String holding the commit SHA1 to analyze, and raises TypeError when it is anything else. The guard is deliberately minimal — it only checks `commit_oid.is_a?(String)`; it does not validate 40-hex formatting, and it runs at the end of initialize after the instance variables are already assigned. The value is used later to diff trees and set git attributes, which is why non-Strings (Rugged::Commit, Rugged::Reference, nil) are rejected up front.

Source

Thrown at lib/linguist/repository.rb:46

    # commit_oid - the sha1 of the commit that will be analyzed;
    #              this is usually the master branch
    # max_tree_size - the maximum tree size to consider for analysis (default: MAX_TREE_SIZE)
    #
    # Returns a Repository
    def initialize(repo, commit_oid, max_tree_size = MAX_TREE_SIZE)
      @repository = if repo.is_a? Linguist::Source::Repository
        repo
      else
        # Allow this for backward-compatibility purposes
        Linguist::Source::RuggedRepository.new(repo)
      end
      @commit_oid = commit_oid
      @max_tree_size = max_tree_size

      @old_commit_oid = nil
      @old_stats = nil

      raise TypeError, 'commit_oid must be a commit SHA1' unless commit_oid.is_a?(String)
    end

    # Public: Load the results of a previous analysis on this repository
    # to speed up the new scan.
    #
    # The new analysis will be performed incrementally as to only take
    # into account the file changes since the last time the repository
    # was scanned
    #
    # old_commit_oid - the sha1 of the commit that was previously analyzed
    # old_stats - the result of the previous analysis, obtained by calling
    #             Repository#cache on the old repository
    #
    # Returns nothing
    def load_existing_stats(old_commit_oid, old_stats)
      @old_commit_oid = old_commit_oid
      @old_stats = old_stats
      nil

View on GitHub (pinned to b45dbe9b28)

Solutions

  1. Resolve to a String oid first: `Linguist::Repository.new(repo, repo.rev_parse_oid('HEAD'))` or pass `commit.oid`.
  2. If you have a Rugged::Reference, use `ref.target_id` (String) rather than `ref.target` (which may be an object).
  3. Add a `unless commit_oid.is_a?(String)` guard at the call site with a clear message before constructing the Repository.
  4. For branch names, resolve once (`repo.branches['main'].target_id`) and reuse the String.

Example fix

# before
stats = Linguist::Repository.new(rugged_repo, rugged_repo.last_commit).language_stats

# after
oid = rugged_repo.rev_parse_oid('HEAD')
stats = Linguist::Repository.new(rugged_repo, oid).language_stats
Defensive patterns

Strategy: type-guard

Validate before calling

# Resolve to a String oid before constructing the Repository
oid =
  case
  when commit_oid.is_a?(String) then commit_oid
  when commit_oid.respond_to?(:oid) then commit_oid.oid        # Rugged::Commit
  when commit_oid.respond_to?(:target_id) then commit_oid.target_id # Rugged::Reference
  else raise TypeError, 'commit_oid must be a commit SHA1'
  end
 Linguist::Repository.new(rugged_repo, oid)

Type guard

def commit_sha1?(obj)
  obj.is_a?(String) && obj.match?(/\A[0-9a-f]{40}\z/i)
end

Try / catch

begin
  Linguist::Repository.new(repo, oid)
rescue TypeError => e
  raise unless e.message == 'commit_oid must be a commit SHA1'
  retry_with(repo.rev_parse_oid('HEAD'))
end

Prevention

When it happens

Trigger: 1) `Linguist::Repository.new(repo, repo.last_commit)` — a Rugged::Commit object, not its oid. 2) Passing `repo.head.target` when it resolves to a Rugged::Reference instead of a String oid. 3) Passing nil or a GitRPC/response object from a hosting app. 4) `Repository.incremental(...)` forwarding a non-String commit_oid. Note the check happens last, so a failed construction still assigned @repository/@commit_oid — do not reuse the half-built object.

Common situations: Code written against Rugged assuming the library accepts commit objects; migrating older linguist call sites where an oid wrapper object was passed; passing the result of ref lookups (Reference/target) instead of resolved oid strings; passing branch name strings like 'main' works type-wise but is not a SHA1 despite the message wording.

Related errors


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