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
trueView on GitHub (pinned to eee0083b38)
Solutions
- Give the primary role at least one host: `web: { hosts: [ "1.2.3.4" ] }`.
- If hosts come from ERB/ENV, make missing values fail loudly (raise in the template) instead of rendering an empty array.
- 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
- Render host lists from ENV with explicit failure: `<%= ENV.fetch("WEB_HOSTS") %>`.
- Run `kamal config` after any change to ERB host templating.
- Keep at least one staging/production host committed per environment overlay.
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
- No servers specified for the #{role.name} role. You can igno
- No servers or accessories specified
- The primary_role #{primary_role_name} isn't defined
- Different roles can't share the same host for SSL: #{duplica
- Conflicting proxy run configurations for host #{host}
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/d7c63419053af48d.
Report an issue: GitHub.