{"record":{"id":"554457753cb0bd83","repo":"basecamp/kamal","slug":"found-hooks-join-these-should-be-renamed","errorCode":null,"errorMessage":"Found #{hooks.join(\", \")}, these should be renamed to (pre|post)-proxy-reboot","messagePattern":"Found #(.+?), these should be renamed to \\(pre\\|post\\)-proxy-reboot","errorType":"validation","errorClass":"Kamal::ConfigurationError","httpStatus":null,"severity":"error","filePath":"lib/kamal/configuration.rb","lineNumber":387,"sourceCode":"    def ensure_valid_kamal_version\n      if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Kamal::VERSION)\n        raise Kamal::ConfigurationError, \"Current version is #{Kamal::VERSION}, minimum required is #{minimum_version}\"\n      end\n\n      true\n    end\n\n    def ensure_retain_containers_valid\n      raise Kamal::ConfigurationError, \"Must retain at least 1 container\" if retain_containers < 1\n\n      true\n    end\n\n    def ensure_no_traefik_reboot_hooks\n      hooks = %w[ pre-traefik-reboot post-traefik-reboot ].select { |hook_file| File.exist?(File.join(hooks_path, hook_file)) }\n\n      if hooks.any?\n        raise Kamal::ConfigurationError, \"Found #{hooks.join(\", \")}, these should be renamed to (pre|post)-proxy-reboot\"\n      end\n\n      true\n    end\n\n    def ensure_one_host_for_ssl_roles\n      roles.each(&:ensure_one_host_for_ssl)\n\n      true\n    end\n\n    def ensure_unique_hosts_for_ssl_roles\n      hosts = roles.select(&:ssl?).flat_map { |role| role.proxy.hosts }\n      duplicates = hosts.tally.filter_map { |host, count| host if count > 1 }\n\n      raise Kamal::ConfigurationError, \"Different roles can't share the same host for SSL: #{duplicates.join(\", \")}\" if duplicates.any?\n\n      true","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/configuration.rb#L369-L405","documentation":"Kamal::Configuration#ensure_no_traefik_reboot_hooks scans the hooks directory (.kamal/hooks by default) for the legacy filenames `pre-traefik-reboot` and `post-traefik-reboot`. Kamal generalized Traefik into a generic proxy, so those hooks became `pre-proxy-reboot`/`post-proxy-reboot`; leaving old-named files raises this error listing the offending filenames so the rename is not silently skipped.","triggerScenarios":"Upgrading a project from an older Kamal that had custom .kamal/hooks/pre-traefik-reboot or post-traefik-reboot scripts without renaming them; restoring a hooks directory from an old backup or template repo.","commonSituations":"Post-upgrade breakage after `bundle update kamal`; copying hooks from an old project; discovering the rename only at deploy time because hook files are not covered by config diffs.","solutions":["Rename the files: `git mv .kamal/hooks/pre-traefik-reboot .kamal/hooks/pre-proxy-reboot` (and likewise post-).","Review the renamed hook's contents — proxy reboot hooks may need updated commands if they referenced traefik-specific behavior.","Commit the rename so teammates and CI do not hit the same error."],"exampleFix":"# shell — before\n.kamal/hooks/pre-traefik-reboot   # triggers error\n.kamal/hooks/post-traefik-reboot\n\n# after\nmv .kamal/hooks/pre-traefik-reboot .kamal/hooks/pre-proxy-reboot\nmv .kamal/hooks/post-traefik-reboot .kamal/hooks/post-proxy-reboot","handlingStrategy":"validation","validationCode":"LEGACY = %w[pre-traefik-reboot post-traefik-reboot]\n\ndef no_legacy_hooks?(hooks_dir = \".kamal/hooks\")\n  LEGACY.none? { |f| File.exist?(File.join(hooks_dir, f)) }\nend","typeGuard":null,"tryCatchPattern":"begin\n  config = Kamal::Configuration.new(create_config_files: false)\nrescue Kamal::ConfigurationError => e\n  puts \"Deploy config invalid: #{e.message}\"\n  exit 1\nend","preventionTips":["After every kamal major upgrade, run `kamal config` once before deploying.","Keep hook filenames in the upgrade checklist; renames like traefik to proxy are breaking.","Version-control .kamal/hooks so renames propagate to the whole team."],"tags":["kamal","hooks","upgrade","proxy","traefik"],"backgroundTag":"breaking-change-rename","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}