basecamp/kamal · error · Kamal::ConfigurationError
Invalid hooks_output '#{level}'#{context}, must be one of: #
Error message
Invalid hooks_output '#{level}'#{context}, must be one of: #{HOOKS_OUTPUT_LEVELS.join(', ')} What it means
Kamal::Configuration#ensure_valid_hooks_output! validates the `hooks_output:` setting — either a single Symbol/String level, or a Hash mapping individual hooks to levels — against HOOKS_OUTPUT_LEVELS, which is exactly [:quiet, :verbose]. Any other value (e.g. `detailed`, `debug`, `info`) raises with the invalid level, the hook context when the failure is hash-keyed, and the allowed list.
Source
Thrown at lib/kamal/configuration.rb:447
end
def role_names
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
end
def ensure_valid_hooks_output!
case raw_config.hooks_output
when Symbol, String
validate_hooks_output_level!(raw_config.hooks_output.to_sym)
when Hash
raw_config.hooks_output.each { |hook, level| validate_hooks_output_level!(level.to_sym, hook) }
end
end
def validate_hooks_output_level!(level, hook = nil)
return if HOOKS_OUTPUT_LEVELS.include?(level)
context = hook ? " for hook '#{hook}'" : ""
raise Kamal::ConfigurationError, "Invalid hooks_output '#{level}'#{context}, must be one of: #{HOOKS_OUTPUT_LEVELS.join(', ')}"
end
def git_version
@git_version ||=
if Kamal::Git.used?
if Kamal::Git.uncommitted_changes.present? && !builder.git_clone?
uncommitted_suffix = "_uncommitted_#{SecureRandom.hex(8)}"
end
[ Kamal::Git.revision, uncommitted_suffix ].compact.join
else
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
end
end
end
View on GitHub (pinned to eee0083b38)
Solutions
- Use one of the two valid levels: `hooks_output: quiet` or `hooks_output: verbose`.
- For per-hook control, use the hash form with valid values: `hooks_output: { pre-deploy: verbose }`.
- If the value comes from ENV, restrict it in the template: `<%= %w[quiet verbose].include?(ENV["HOOKS_OUTPUT"]) ? ENV["HOOKS_OUTPUT"] : "quiet" %>`.
Example fix
# config/deploy.yml — before hooks_output: detailed # after hooks_output: verbose
Defensive patterns
Strategy: validation
Validate before calling
LEVELS = %i[quiet verbose].freeze
def valid_hooks_output?(value)
case value
when String, Symbol then LEVELS.include?(value.to_sym)
when Hash then value.values.all? { |v| LEVELS.include?(v.to_sym) }
else true # nil is fine (default)
end
end Type guard
def kamal_hooks_output?(value)
return true if value.nil?
case value
when String, Symbol then %w[quiet verbose].include?(value.to_s)
when Hash then value.values.all? { |v| %w[quiet verbose].include?(v.to_s) }
else false
end
end Try / catch
begin
config = Kamal::Configuration.new(create_config_files: false)
rescue Kamal::ConfigurationError => e
puts "Deploy config invalid: #{e.message}"
exit 1
end Prevention
- Restrict ENV-driven values to a whitelist in the ERB template.
- Check Kamal::Configuration::HOOKS_OUTPUT_LEVELS after upgrading kamal.
- Use the Hash form only when individual hooks need different levels.
When it happens
Trigger: Setting `hooks_output: detailed` (or any word other than quiet/verbose) in config/deploy.yml; a Hash form like `hooks_output: { "pre-deploy": "info" }`; values sourced from ENV strings that were never whitelisted; configs written against docs from a different kamal version whose level names changed.
Common situations: Guessing verbosity level names instead of checking constants; copying CI log-level conventions (info/debug) into kamal config; per-hook overrides added without validating each value.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Missing required configuration for #{key}
- Service name can only include alphanumeric characters, hyphe
- Invalid cache type: #{@options["cache"]["type"]}
- #{error_context}#{message}
- file path is required
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/ae822df85247fb4d.
Report an issue: GitHub.