basecamp/kamal · error · Kamal::ConfigurationError

No servers specified for the #

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.

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.

Appendix: 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)