basecamp/kamal · error · Kamal::ConfigurationError
accessories/#{name}: unknown role #{accessory_config["role"]
Error message
accessories/#{name}: unknown role #{accessory_config["role"]} What it means
Kamal::Configuration::Accessory#ensure_valid_roles also handles the singular form: an accessory with `role:` (place this accessory on every host of that one role) is checked with config.role(name), and if no such role exists this Kamal::ConfigurationError is raised with the accessory name and the unknown role. It is the single-role counterpart to the plural `roles:` check.
Source
Thrown at lib/kamal/configuration/accessory.rb:277
def extract_hosts_from_config_with_tag(tag)
if (servers_with_roles = config.raw_config.servers).is_a?(Hash)
servers_with_roles.flat_map do |role, servers_in_role|
servers_in_role.filter_map do |host|
host.keys.first if host.is_a?(Hash) && host.values.first.include?(tag)
end
end
end
end
def network
accessory_config["network"] || DEFAULT_NETWORK
end
def ensure_valid_roles
if accessory_config["roles"] && (missing_roles = accessory_config["roles"] - config.roles.map(&:name)).any?
raise Kamal::ConfigurationError, "accessories/#{name}: unknown roles #{missing_roles.join(", ")}"
elsif accessory_config["role"] && !config.role(accessory_config["role"])
raise Kamal::ConfigurationError, "accessories/#{name}: unknown role #{accessory_config["role"]}"
end
end
end
View on GitHub (pinned to eee0083b38)
Solutions
- Set `role:` to a key that exists under `servers:` (verify via `kamal config`).
- Or switch addressing modes: use `host: 1.2.3.4` or `hosts: [...]` if the accessory should run on specific machines rather than alongside a role.
- Grep the config for other references to the old name after any role rename.
Example fix
# config/deploy.yml — before
servers:
web:
- 1.2.3.4
accessories:
mysql:
role: db
# after
servers:
web:
- 1.2.3.4
accessories:
mysql:
host: 1.2.3.9 Defensive patterns
Strategy: validation
Validate before calling
def accessory_role_valid?(raw)
role_names = raw["servers"].is_a?(Array) ? ["web"] : raw["servers"].keys.map(&:to_s)
raw["accessories"].to_h.all? do |_name, cfg|
cfg["role"].nil? || role_names.include?(cfg["role"].to_s)
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
- Validate role references in a config-lint step in CI.
- Use host:/hosts: addressing for accessories tied to machines rather than roles.
- Keep a single source of truth for role names (e.g. a YAML anchor list) reused by servers and accessories.
When it happens
Trigger: An accessory declaring `role: db` when servers define only `web`/`workers`; a role rename that missed the accessory's `role:` key; singular `role:` pointing at a name that only exists as an accessory name, not a server role.
Common situations: Copy-paste of accessory blocks between projects; renaming roles in servers without grepping accessories; confusion between `role:` (must match a servers role) and `host:`/`hosts:` addressing.
Related errors
- Conflicting proxy run configurations for host #{host}
- accessories/#{name}: unknown roles #{missing_roles.join(", "
- The primary_role #{primary_role_name} isn't defined
- No servers specified for the #{primary_role.name} primary_ro
- No servers specified for the #{role.name} role. You can igno
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/d3315a8ef34e052d.
Report an issue: GitHub.