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
nilView on GitHub (pinned to b45dbe9b28)
Solutions
- Resolve to a String oid first: `Linguist::Repository.new(repo, repo.rev_parse_oid('HEAD'))` or pass `commit.oid`.
- If you have a Rugged::Reference, use `ref.target_id` (String) rather than `ref.target` (which may be an object).
- Add a `unless commit_oid.is_a?(String)` guard at the call site with a clear message before constructing the Repository.
- 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
- Always resolve refs with rev_parse_oid / branch.target_id so you pass Strings, never Rugged objects.
- The guard only checks String-ness — also assert 40-hex format yourself to catch branch names and garbage early.
- Note the check runs at the END of initialize; a raised TypeError still leaves instance vars set, so do not reuse the object.
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
- can't convert #{obj.inspect} into String
- Duplicate language name: #{language.name}
- Duplicate language name: #{language.fs_name}
- Duplicate alias: #{name}
- Extension is missing a '.': #{extension.inspect}
AI-assisted analysis of github-linguist/linguist@b45dbe9b28 (2026-08-21).
Data as JSON: /api/errors/9c9804eefd258dc6.
Report an issue: GitHub.