whitesmith/rubycritic · error · RuntimeError

Could not create reporter for class #{path}. Error: #{error}

Error message

Could not create reporter for class #{path}. Error: #{error}!

What it means

RubyCritic resolves each custom formatter spec (from --custom-format on the CLI or the :formatters config option) into a Ruby class by walking the constant path: path.split('::').inject(Object) { |obj, klass| obj.const_get klass } in lib/rubycritic/reporter.rb:33-37. When any segment of that lookup raises NameError (uninitialized constant, wrong constant name, or a missing nesting level), RubyCritic catches it and re-raises this RuntimeError wrapping the original NameError text. It means the formatter file may have loaded fine, but the class named in your formatter spec was not found at that constant path when the report was generated.

Source

Thrown at lib/rubycritic/reporter.rb:36

        require "rubycritic/generators/#{config_format}_report"
        Generator.const_get("#{config_format.capitalize}Report")
      else
        require 'rubycritic/generators/html_report'
        Generator::HtmlReport
      end
    end

    def self.report_generator_class_from_formatter(formatter)
      require_path, class_name = formatter.sub(/([^:]):([^:])/, '\1\;\2').split('\;', 2)
      class_name ||= require_path
      require require_path unless require_path == class_name
      class_from_path(class_name)
    end

    def self.class_from_path(path)
      path.split('::').inject(Object) { |obj, klass| obj.const_get klass }
    rescue NameError => error
      raise "Could not create reporter for class #{path}. Error: #{error}!"
    end
  end
end

View on GitHub (pinned to a70e68cdee)

Solutions

  1. Fix the class name in the --custom-format spec to the exact constant: correct CamelCase and full namespace, e.g. `--custom-format my_formatter:MyFormatter` or `--custom-format my_gem:MyGem::MyFormatter`.
  2. If you pass only a class name (no `:` separator), require the formatter file yourself before the task — in the Rakefile put `require 'my_formatter'` above `RubyCritic::RakeTask.new` — because RubyCritic skips the require when require path and class name are identical.
  3. Prefer the `requirepath:Class::Name` form (e.g. `rubycritic --custom-format my_formatter:MyFormatter`) so RubyCritic performs the require for you.
  4. Verify the constant loads standalone in the same context: `bundle exec ruby -e "require 'my_formatter'; p MyFormatter"` — if this fails, fix the gem's load path or Gemfile inclusion first.
  5. Check for a namespace/file-name mismatch: the class must exist at top level (Object) unless you spell out the full `Namespace::Chain` in the spec. A LoadError instead of this message means the require path itself is wrong or the gem is not installed.
  6. If the formatter gem changed in a recent upgrade, check its CHANGELOG for renamed or moved formatter classes and pin the known-good version until you update the spec.

Example fix

# before (Rakefile) — class never loaded, spec has no require path:
RubyCritic::RakeTask.new do |task|
  task.options = '--custom-format MyFormatter'
end
# => RuntimeError: Could not create reporter for class MyFormatter.
#    Error: uninitialized constant MyFormatter!

# after — require the file first, and pass require path + class name:
require 'my_formatter'

RubyCritic::RakeTask.new do |task|
  task.options = '--custom-format my_formatter:MyFormatter'
end

# for a namespaced formatter, spell out the full constant path:
#   rubycritic --custom-format my_gem:MyGem::MyFormatter
Defensive patterns

Strategy: validation

Validate before calling

# Run before invoking RubyCritic (rake task or API) to fail fast with a clear
# message instead of the generic RuntimeError mid-report. Splits the spec on the
# first single colon (not part of '::'), mirrors the library's require logic, and
# checks the constant path resolves to a Class implementing #generate_report.
def rubycritic_formatter_resolvable?(spec)
  require_path, class_name = spec.split(/:(?!:)/, 2)
  class_name ||= require_path
  require require_path unless require_path == class_name
  klass = class_name.split('::').inject(Object) do |mod, name|
    return false unless mod.const_defined?(name.to_sym)
    mod.const_get(name.to_sym)
  end
  klass.is_a?(Class) && klass.public_method_defined?(:generate_report)
rescue LoadError, NameError
  false
end

RubyCritic::Config.formatters.all? { |s| rubycritic_formatter_resolvable?(s) } or
  abort 'formatter spec is not resolvable — check class name casing/namespace'

Type guard

# Ruby 'type guard': predicate that a formatter spec resolves to a Class
# implementing the formatter interface (#generate_report, initialized with
# analysed_modules).
def valid_rubycritic_formatter?(spec)
  require_path, class_name = spec.split(/:(?!:)/, 2)
  class_name ||= require_path
  require require_path unless require_path == class_name
  klass = class_name.split('::').inject(Object) do |mod, name|
    return false unless mod.const_defined?(name.to_sym)
    mod.const_get(name.to_sym)
  end
  klass.is_a?(Class) && klass.public_method_defined?(:generate_report)
rescue StandardError
  false
end

Try / catch

# The library raises a plain RuntimeError (string message, no dedicated error
# class), so match on the message prefix and rescue narrowly — keep other
# errors fatal.
begin
  RubyCritic::Reporter.generate_report(analysed_modules)
rescue RuntimeError => e
  raise unless e.message.start_with?('Could not create reporter for class')
  warn "Custom formatter failed to load: #{e.message}"
  warn 'Check the class name casing/namespace, or require the formatter file first.'
  exit 1
end

Prevention

When it happens

Trigger: Calling `rubycritic --custom-format <requirepath>:<Class::Name>` (or setting RubyCritic::Config.formatters / the rake task's options with --custom-format) where: (1) the class name is misspelled or wrongly cased — e.g. `my_formatter` instead of `MyFormatter`, which makes Object#const_get raise 'wrong constant name'; (2) the class is namespaced, e.g. defined as MyGem::MyFormatter, but the spec passes only `MyFormatter` or the wrong nesting; (3) the spec is class-name-only (no `:` separator) — RubyCritic then skips the require entirely (reporter.rb:29 requires only when require_path != class_name), so unless your Rakefile already required the file, the constant is never loaded; (4) the require path resolved but the file defines a differently-named class.

Common situations: Following the docs' Rakefile example but forgetting `require 'my_formatter'` before `RubyCritic::RakeTask.new`; running rubycritic from the CLI with only a class name for a formatter that lives in a gem you never required; copy-pasting a formatter spec where the file is snake_case and passing the snake_case string as the class name; upgrading a formatter gem (e.g. rubycritic-small-badge) whose class moved or was renamed between versions; environments where the formatter is autoloaded in the app (Zeitwerk) but not on the rubycritic CLI process.


AI-assisted analysis of whitesmith/rubycritic@a70e68cdee (2026-08-23). Data as JSON: /api/errors/d62d0549d1054f95. Report an issue: GitHub.