{"record":{"id":"a49536a25658ece6","repo":"sds/overcommit","slug":"class-hook-name-is-not-a-subclass-of-hook-bas","errorCode":null,"errorMessage":"Class #{hook_name} is not a subclass of #{hook_base_class}.","messagePattern":"Class #(.+?) is not a subclass of #(.+?)\\.","errorType":"exception","errorClass":"Overcommit::Exceptions::HookLoadError","httpStatus":null,"severity":"error","filePath":"lib/overcommit/hook_loader/base.rb","lineNumber":33,"sourceCode":"    # When implemented in subclasses, loads the hooks for which that subclass is\n    # responsible.\n    #\n    # @return [Array<Hook>]\n    def load_hooks\n      raise NotImplementedError\n    end\n\n    private\n\n    attr_reader :log\n\n    # Load and return a {Hook} from a CamelCase hook name.\n    def create_hook(hook_name)\n      hook_type_class = Overcommit::Hook.const_get(@context.hook_class_name)\n      hook_base_class = hook_type_class.const_get(:Base)\n      hook_class = hook_type_class.const_get(hook_name)\n      unless hook_class < hook_base_class\n        raise Overcommit::Exceptions::HookLoadError,\n              \"Class #{hook_name} is not a subclass of #{hook_base_class}.\"\n      end\n\n      begin\n        Overcommit::Hook.const_get(@context.hook_class_name).\n                         const_get(hook_name).\n                         new(@config, @context)\n      rescue LoadError, NameError => e\n        raise Overcommit::Exceptions::HookLoadError,\n              \"Unable to load hook '#{hook_name}': #{e}\",\n              e.backtrace\n      end\n    end\n  end\nend\n","sourceCodeStart":15,"sourceCodeEnd":49,"githubUrl":"https://github.com/sds/overcommit/blob/fee0cd74b26eb81f64b43b7fab17bbb541575cc4/lib/overcommit/hook_loader/base.rb#L15-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the class named in the error inherit from the base class shown in the message, e.g. 'class MyPlugin < Overcommit::Hook::PreCommit::Base'","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","Rename helper classes that shadow the file name so the constant resolves to the real hook class","If plugin signatures are enabled, run 'overcommit --sign <hook-type>' after the fix so the modified plugin re-signs"],"exampleFix":"# before (.overcommit/plugins/pre_commit/my_plugin.rb)\nmodule Overcommit::Hook::PreCommit\n  class MyPlugin\n    def run; end\n  end\nend\n\n# after\nmodule Overcommit::Hook::PreCommit\n  class MyPlugin < Base\n    def run\n      :pass\n    end\n  end\nend","handlingStrategy":"validation","validationCode":"hook_type = Overcommit::Hook.const_get(context.hook_class_name)\nbase = hook_type.const_get(:Base)\nname = Overcommit::Utils.camel_case(File.basename(plugin_path, '.rb'))\nraise \"plugin defines no #{name} class\" unless hook_type.const_defined?(name)\nraise \"#{name} must subclass #{base}\" unless hook_type.const_get(name) < base","typeGuard":"def valid_plugin?(hook_type_name, hook_name)\n  mod = Overcommit::Hook.const_get(hook_type_name)\n  mod.const_defined?(hook_name) && mod.const_get(hook_name) < mod.const_get(:Base)\nrescue NameError\n  false\nend","tryCatchPattern":"begin\n  runner.run\nrescue Overcommit::Exceptions::HookLoadError => e\n  $stderr.puts \"Bad plugin definition: #{e.message}\"\n  exit 1\nend","preventionTips":["Start plugins from an existing built-in hook or template so the Base superclass is already correct","Keep one hook class per plugin file, named exactly after the file","Add a CI task that requires every file under .overcommit/plugins to catch bad definitions before teammates pull them"],"tags":["ruby","overcommit","plugin","class-hierarchy","const-get"],"backgroundTag":"subclass-validation-failed","analyzedSha":"fee0cd74b26eb81f64b43b7fab17bbb541575cc4","analyzedAt":"2026-08-23T04:07:28.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}