sds/overcommit · error · Overcommit::Exceptions::HookLoadError

Class #{hook_name} is not a subclass of #{hook_base_class}.

Error message

Class #{hook_name} is not a subclass of #{hook_base_class}.

What it means

Overcommit resolves each hook by its CamelCase name under the hook type module (e.g. Overcommit::Hook::PreCommit) and requires it to inherit that type's Base class (e.g. Overcommit::Hook::PreCommit::Base). This error means the constant was found but the subclass test (hook_class < hook_base_class in Base#create_hook) failed. Overcommit rejects the class because it would not implement the hook lifecycle API (run, enabled?, skip) that HookRunner depends on.

Source

Thrown at lib/overcommit/hook_loader/base.rb:33

    # When implemented in subclasses, loads the hooks for which that subclass is
    # responsible.
    #
    # @return [Array<Hook>]
    def load_hooks
      raise NotImplementedError
    end

    private

    attr_reader :log

    # Load and return a {Hook} from a CamelCase hook name.
    def create_hook(hook_name)
      hook_type_class = Overcommit::Hook.const_get(@context.hook_class_name)
      hook_base_class = hook_type_class.const_get(:Base)
      hook_class = hook_type_class.const_get(hook_name)
      unless hook_class < hook_base_class
        raise Overcommit::Exceptions::HookLoadError,
              "Class #{hook_name} is not a subclass of #{hook_base_class}."
      end

      begin
        Overcommit::Hook.const_get(@context.hook_class_name).
                         const_get(hook_name).
                         new(@config, @context)
      rescue LoadError, NameError => e
        raise Overcommit::Exceptions::HookLoadError,
              "Unable to load hook '#{hook_name}': #{e}",
              e.backtrace
      end
    end
  end
end

View on GitHub (pinned to fee0cd74b2)

Solutions

  1. Make the class named in the error inherit from the base class shown in the message, e.g. 'class MyPlugin < Overcommit::Hook::PreCommit::Base'
  2. Confirm the class name is the CamelCase form of the plugin file name (my_plugin.rb -> MyPlugin) inside the module for that hook type directory
  3. Rename helper classes that shadow the file name so the constant resolves to the real hook class
  4. If plugin signatures are enabled, run 'overcommit --sign <hook-type>' after the fix so the modified plugin re-signs

Example fix

# before (.overcommit/plugins/pre_commit/my_plugin.rb)
module Overcommit::Hook::PreCommit
  class MyPlugin
    def run; end
  end
end

# after
module Overcommit::Hook::PreCommit
  class MyPlugin < Base
    def run
      :pass
    end
  end
end
Defensive patterns

Strategy: validation

Validate before calling

hook_type = Overcommit::Hook.const_get(context.hook_class_name)
base = hook_type.const_get(:Base)
name = Overcommit::Utils.camel_case(File.basename(plugin_path, '.rb'))
raise "plugin defines no #{name} class" unless hook_type.const_defined?(name)
raise "#{name} must subclass #{base}" unless hook_type.const_get(name) < base

Type guard

def valid_plugin?(hook_type_name, hook_name)
  mod = Overcommit::Hook.const_get(hook_type_name)
  mod.const_defined?(hook_name) && mod.const_get(hook_name) < mod.const_get(:Base)
rescue NameError
  false
end

Try / catch

begin
  runner.run
rescue Overcommit::Exceptions::HookLoadError => e
  $stderr.puts "Bad plugin definition: #{e.message}"
  exit 1
end

Prevention

When it happens

Trigger: A plugin file loaded from .overcommit/plugins/<hook_type>/ defines or reopens the constant matching its CamelCase file name without inheriting from the hook type's Base - e.g. 'module Overcommit::Hook::PreCommit; class MyPlugin; end; end' with no superclass - or a helper class shadows the name derived from the file name. Raised during load_hooks -> create_hook.

Common situations: Writing a first custom plugin and forgetting the '< Overcommit::Hook::PreCommit::Base' superclass; pasting a plugin template into the wrong hook type namespace; plugin files that only define helper classes and constants.

Related errors


AI-assisted analysis of sds/overcommit@fee0cd74b2 (2026-08-23). Data as JSON: /api/errors/a49536a25658ece6. Report an issue: GitHub.