basecamp/kamal · error · ArgumentError
No --hosts match for #{hosts.join(',')}
Error message
No --hosts match for #{hosts.join(',')} What it means
Kamal::Commander#specific_hosts= is called when you pass the global --hosts filter (e.g. `kamal deploy --hosts 1.2.3.4,5.6.7.8`). It filters config.all_hosts with Kamal::Utils.filter_specific_items (fnmatch with FNM_EXTGLOB, so wildcards/extended globs are allowed). If none of the configured hosts match any filter, the result is empty and Kamal raises ArgumentError ('No --hosts match for ...').
Source
Thrown at lib/kamal/commander.rb:68
else
self.specific_hosts = [ config.primary_host ]
end
end
def specific_roles=(role_names)
@specifics = nil
@specific_roles = if role_names.present?
filtered = Kamal::Utils.filter_specific_items(role_names, config.roles)
raise ArgumentError, "No --roles match for #{role_names.join(',')}" if filtered.empty?
filtered
end
end
def specific_hosts=(hosts)
@specifics = nil
@specific_hosts = if hosts.present?
filtered = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)
raise ArgumentError, "No --hosts match for #{hosts.join(',')}" if filtered.empty?
filtered
end
end
def with_specific_hosts(hosts)
original_hosts, self.specific_hosts = specific_hosts, hosts
yield
ensure
self.specific_hosts = original_hosts
end
def accessory_names
config.accessories&.collect(&:name) || []
end
def app(role: nil, host: nil)
Kamal::Commands::App.new(config, role: role, host: host)
endView on GitHub (pinned to eee0083b38)
Solutions
- Check the hosts defined in your config (`kamal app details` or read the servers: blocks in config/deploy*.yml) and pass exactly those names/IPs to --hosts.
- If using a destination (-d), remember host lists come from deploy.<destination>.yml — verify you filtered with values from that file.
- Use fnmatch-compatible patterns ('203.0.113.*') since regex alternation is not supported.
- If you meant to select by role, use --roles <role-name> instead.
Example fix
# before # config/deploy.yml servers web: hosts: 203.0.113.10, 203.0.113.11 kamal deploy --hosts 10.0.0.10 # internal IP not in config # after kamal deploy --hosts 203.0.113.10 # or pattern-match a subnet: kamal deploy --hosts '203.0.113.*'
Defensive patterns
Strategy: validation
Validate before calling
require "yaml"
config = YAML.load_file("config/deploy#{ENV["KAMAL_DESTINATION"] ? ".#{ENV["KAMAL_DESTINATION"]}" : ""}.yml")
hosts = config["servers"].values.flat_map { |r| Array(r["hosts"]) }
abort "host not in config" unless hosts.any? { |h| File.fnmatch(ARGV[0], h.to_s) } Type guard
def hosts_match?(filters, configured_hosts)
filters.any? { |f| configured_hosts.any? { |h| File.fnmatch(f, h.to_s, File::FNM_EXTGLOB) } }
end Try / catch
begin
Kamal::Commander.new.specific_hosts = %w[203.0.113.10]
rescue ArgumentError => e
raise unless e.message.include?("--hosts")
abort "check host names in deploy config: #{e.message}"
end Prevention
- Source --hosts values from the same deploy.yml (or IaC output) rather than hardcoding IPs in scripts.
- When using destinations, validate against the destination overlay's host list, not the base file.
- Prefer --roles for group targeting; use --hosts for single-host ops.
When it happens
Trigger: `kamal deploy --hosts 10.0.0.9` when config lists only public hostnames; a glob matching no host (`--hosts 'db-*'`); typo'd or stale IPs after infrastructure changes; passing a role name instead of a hostname to --hosts; quoting that leaves brackets/commas attached to the filter string.
Common situations: Hosts changed in deploy.yml but runbooks/CI still pass old IPs; environments (destinations) with different host sets; SSH-config aliases that differ from the hosts in deploy.yml; copying a --roles example and using it for --hosts.
Related errors
- No --roles match for #{role_names.join(',')}
- Raw is not compatible with interactive
- Detach is not compatible with #{incompatible_options.join("
- Raw is not compatible with #{incompatible_options.join(" or
- No command provided. You must specify a command to execute.
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/dafc7b22e9bf7871.
Report an issue: GitHub.