NoMethodError in DesignManagement::Repository#full_path when project is nil during Geo replication
Summary
A NoMethodError is raised in DesignManagement::Repository#full_path when the associated project is nil. This occurs during Geo replication when a DesignManagement::Repository record exists but its associated project has been deleted, leaving an orphaned record.
Error
NoMethodError: undefined method `full_path' for nil (NoMethodError)
project.full_path + repo_type.path_suffix
^^^^^^^^^^
from app/models/design_management/repository.rb:26:in `full_path'Call chain
Geo::EventWorker#performpicks up a Geo replication event (created/updated).Geo::DesignManagementRepositoryReplicator#repositorycallsmodel_record.repository.DesignManagement::Repository#repositorycalls#full_path.DesignManagement::Repository#full_pathexecutesproject.full_path + repo_type.path_suffix, butprojectisnil.
The with_record_not_found_handling wrapper in Gitlab::Geo::Replicator only rescues ActiveRecord::RecordNotFound, so the NoMethodError escapes.
Root cause
A DesignManagement::Repository record exists in the database whose associated project has been deleted (orphaned record). The Geo secondary node received a replication event for this repository, but when it tries to resolve the record, the project is gone.
Proposed fix
Add a nil guard for project in both full_path and disk_path methods in app/models/design_management/repository.rb, raising ActiveRecord::RecordNotFound instead of letting a NoMethodError bubble up:
def full_path
raise ActiveRecord::RecordNotFound, "Project not found for DesignManagement::Repository ##{id}" unless project
project.full_path + repo_type.path_suffix
end
def disk_path
raise ActiveRecord::RecordNotFound, "Project not found for DesignManagement::Repository ##{id}" unless project
project.disk_path + repo_type.path_suffix
endThis approach:
- Keeps the fix scoped to the model where the
nilis encountered, rather than broadening the rescue in the shared Geo replicator. - The existing
with_record_not_found_handlinginGitlab::Geo::Replicatorwill catch theActiveRecord::RecordNotFoundnaturally. - The error message is descriptive about what wasn't found (the project, not the
DesignManagement::Repositoryitself). - Non-Geo callers also get a clear error instead of a cryptic
NoMethodErroronnil.