basecamp/kamal · error · Kamal::ConfigurationError

No servers specified for the #{primary_role.name} primary_ro

Error message

No servers specified for the #{primary_role.name} primary_role

What it means

Kamal::Configuration#ensure_required_keys_present checks that the primary role — which does exist as a key under `servers:` — has a non-empty hosts list. A role entry with empty hosts (e.g. `web: { hosts: [] }` or an ERB-rendered empty array) means Kamal has no machine to run migrations, health checks, or traffic switching on, so validation aborts with the role name interpolated into the message.

Source

Thrown at lib/kamal/configuration.rb:348

      true
    end

    def ensure_required_keys_present
      %i[ service registry ].each do |key|
        raise Kamal::ConfigurationError, "Missing required configuration for #{key}" unless raw_config[key].present?
      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

View on GitHub (pinned to eee0083b38)

Solutions

  1. Give the primary role at least one host: `web: { hosts: [ "1.2.3.4" ] }`.
  2. If hosts come from ERB/ENV, make missing values fail loudly (raise in the template) instead of rendering an empty array.
  3. Verify with `kamal config` (or `kamal config roles`) that the rendered hosts list is what you expect before deploying.

Example fix

# config/deploy.yml — before
servers:
  web:
    hosts: <%= ENV["WEB_HOSTS"]&.split(",") %>

# after
servers:
  web:
    hosts: <%= (ENV["WEB_HOSTS"] or raise "WEB_HOSTS not set").split(",") %>
Defensive patterns

Strategy: validation

Validate before calling

def primary_role_has_hosts?(path = "config/deploy.yml")
  raw = YAML.safe_load(ERB.new(File.read(path)).result, aliases: true) || {}
  primary = raw["primary_role"] || "web"
  entry = raw["servers"][primary] rescue nil
  hosts = entry.is_a?(Hash) ? entry["hosts"] : entry
  Array(hosts).any? { |h| (h.is_a?(Hash) ? h.keys.first : h).to_s != "" }
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: { hosts: [] } }` after ERB renders an empty list because the source env var or loop produced nothing; a hosts list built from `<%= ENV["WEB_HOSTS"]&.split(",") %>` that yields an empty array; a YAML role key with no hosts value at all.

Common situations: Templated multi-environment configs where one environment has no web hosts yet; stashing hosts in ENV and forgetting to export it in the deploy shell; refactoring hosts from an inline array to ERB and silently breaking it.

Related errors


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