basecamp/kamal · error · Kamal::ConfigurationError

No servers specified for the #{role.name} role. You can igno

Error message

No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true

What it means

After validating the primary role, Kamal iterates every role and requires each non-primary role to have at least one host, unless `allow_empty_roles: true` is set. This Kamal::ConfigurationError fires for the first role whose hosts array is empty, with the role name in the message and a pointer to the escape hatch. The check exists because silently skipping an empty role usually masks a templating mistake.

Source

Thrown at lib/kamal/configuration.rb:354

      end

      raise Kamal::ConfigurationError, "Missing required configuration for image" if image.blank?

      if raw_config.servers.nil?
        raise Kamal::ConfigurationError, "No servers or accessories specified" unless raw_config.accessories.present?
      else
        unless role(primary_role_name).present?
          raise Kamal::ConfigurationError, "The primary_role #{primary_role_name} isn't defined"
        end

        if primary_role.hosts.empty?
          raise Kamal::ConfigurationError, "No servers specified for the #{primary_role.name} primary_role"
        end

        unless allow_empty_roles?
          roles.each do |role|
            if role.hosts.empty?
              raise Kamal::ConfigurationError, "No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true"
            end
          end
        end
      end

      true
    end

    def ensure_valid_service_name
      raise Kamal::ConfigurationError, "Service name can only include alphanumeric characters, hyphens, and underscores" unless raw_config[:service] =~ /^[a-z0-9_-]+$/i

      true
    end

    def ensure_valid_kamal_version
      if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Kamal::VERSION)
        raise Kamal::ConfigurationError, "Current version is #{Kamal::VERSION}, minimum required is #{minimum_version}"
      end

View on GitHub (pinned to eee0083b38)

Solutions

  1. Populate the empty role's hosts list if the role should really deploy.
  2. If the role is legitimately empty in this environment, add top-level `allow_empty_roles: true` (or set it per environment).
  3. Remove the role key entirely if you no longer need it — cleaner than keeping an empty entry.
  4. Make ERB host lists raise on missing input rather than rendering [].

Example fix

# config/deploy.yml — before
servers:
  web:
    - 1.2.3.4
  workers:
    hosts: []

# after
allow_empty_roles: true
servers:
  web:
    - 1.2.3.4
  workers:
    hosts: []
Defensive patterns

Strategy: validation

Validate before calling

def roles_have_hosts_unless_allowed?(path = "config/deploy.yml")
  raw = YAML.safe_load(ERB.new(File.read(path)).result, aliases: true) || {}
  return true if raw["allow_empty_roles"]
  primary = raw["primary_role"] || "web"
  raw["servers"].to_a.all? do |name, entry|
    hosts = entry.is_a?(Hash) ? entry["hosts"] : entry
    name == primary || Array(hosts).any?
  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: `servers: { web: [...], workers: { hosts: [] } }` with no `allow_empty_roles: true`; ERB-generated role hosts (e.g. sidekiq hosts from an env var) that render empty in one environment; a role temporarily emptied while migrating infrastructure.

Common situations: Multi-environment configs where workers exist in production but not staging; host lists driven by ENV that are unset locally; role pruning during scale-down that leaves the key behind.

Related errors


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