basecamp/kamal · error · Kamal::ConfigurationError

accessories/#{name}: unknown roles #{missing_roles.join(", "

Error message

accessories/#{name}: unknown roles #{missing_roles.join(", ")}

What it means

Kamal::Configuration::Accessory#ensure_valid_roles validates an accessory's `roles:` array (the roles whose hosts the accessory should run on) against the names of roles actually defined under `servers:`. Any name not found there is collected and reported in this Kamal::ConfigurationError, prefixed with the accessory name so you know which YAML block is at fault.

Source

Thrown at lib/kamal/configuration/accessory.rb:275

    end

    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

  1. Align the accessory's `roles:` entries with the exact keys under `servers:` (check spelling and singular/plural).
  2. If the role was renamed, update the accessory to the new name.
  3. Run `kamal config` to list the actual role names before fixing the accessory.

Example fix

# config/deploy.yml — before
servers:
  web:
    - 1.2.3.4
  workers:
    - 1.2.3.5
accessories:
  redis:
    roles: [ "sidekiq" ]

# after
servers:
  web:
    - 1.2.3.4
  workers:
    - 1.2.3.5
accessories:
  redis:
    roles: [ "workers" ]
Defensive patterns

Strategy: validation

Validate before calling

def accessory_roles_valid?(raw)
  role_names = raw["servers"].is_a?(Array) ? ["web"] : raw["servers"].keys.map(&:to_s)
  raw["accessories"].to_h.all? do |_name, cfg|
    Array(cfg["roles"]).all? { |r| role_names.include?(r.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

When it happens

Trigger: An accessory in config/deploy.yml declaring `roles: [ "sidekiq" ]` when servers define `workers:` instead; renaming a role without updating accessories referencing it; a plural `roles:` array containing one valid and one misspelled role name — the missing ones are listed in the message.

Common situations: Role renames during refactors that miss accessory references; copy-pasted accessory configs from another project with different role names; singular/plural confusion between `role` and `roles` keys.

Related errors


AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21). Data as JSON: /api/errors/74cd311f41499f49. Report an issue: GitHub.