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

Unable to load hook '#{hook_name}': #{e}

Error message

Unable to load hook '#{hook_name}': #{e}

What it means

Raised when instantiating a hook class fails with LoadError or NameError after the class resolved. Base#create_hook calls Hook::<Type>.const_get(hook_name).new(config, context) and wraps any LoadError/NameError as HookLoadError, keeping the original message and backtrace, because the missing constant or file usually points to an unloaded gem or a plugin file/class name mismatch.

Source

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

    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. Read the tail of the message after the colon - it carries the original NameError/LoadError naming the missing constant or file; fix that first
  2. If a gem constant is missing, add the require at the top of the plugin file and add the gem to the bundle
  3. If the hook class was never defined, make the class name the exact CamelCase of the file name (my_check.rb -> MyCheck) inside the correct hook module
  4. If the dependency lives in another plugin, load it with require_relative or inline it so load order cannot break

Example fix

# before (.overcommit/plugins/pre_commit/json_lint.rb)
module Overcommit::Hook::PreCommit
  class JsonLint < Base
    def run
      JsLint.check(applicable_files) # NameError: uninitialized constant JsLint
    end
  end
end

# after
require 'js_lint'

module Overcommit::Hook::PreCommit
  class JsonLint < Base
    def run
      JsLint.check(applicable_files)
    end
  end
end
Defensive patterns

Strategy: try-catch

Validate before calling

# CI smoke test: every plugin must load standalone
Dir[File.expand_path('.overcommit/plugins/**/*.rb')].sort.each { |f| require f }

Try / catch

begin
  hooks = Overcommit::HookLoader::PluginHookLoader.new(config, context, logger).load_hooks
rescue Overcommit::Exceptions::HookLoadError => e
  warn "Plugin failed to load: #{e.message}"
  warn e.backtrace.first(5)
  exit 78 # EX_CONFIG
end

Prevention

When it happens

Trigger: The plugin class body or its initialize references an uninitialized constant (e.g. a gem class never required); the plugin file never defined the expected CamelCase constant so const_get(hook_name) raises NameError (file my_check.rb defining class MyChek); or plugin code calls require on a file or gem that cannot be found.

Common situations: Plugin uses a gem constant without requiring the gem; typo between plugin file name and class name; plugin depends on a constant defined in another plugin file that sorts later during load; an Overcommit upgrade renamed a hook class the plugin reopened.

Related errors


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