{"record":{"id":"038926b0d6697a68","repo":"basecamp/kamal","slug":"no-roles-match-for-role-names-join","errorCode":null,"errorMessage":"No --roles match for #{role_names.join(',')}","messagePattern":"No --roles match for #(.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/kamal/commander.rb","lineNumber":59,"sourceCode":"\n  def configured?\n    @config || @config_kwargs\n  end\n\n  def specific_primary!\n    @specifics = nil\n    if specific_roles.present?\n      self.specific_hosts = [ specific_roles.first.primary_host ]\n    else\n      self.specific_hosts = [ config.primary_host ]\n    end\n  end\n\n  def specific_roles=(role_names)\n    @specifics = nil\n    @specific_roles = if role_names.present?\n      filtered = Kamal::Utils.filter_specific_items(role_names, config.roles)\n      raise ArgumentError, \"No --roles match for #{role_names.join(',')}\" if filtered.empty?\n      filtered\n    end\n  end\n\n  def specific_hosts=(hosts)\n    @specifics = nil\n    @specific_hosts = if hosts.present?\n      filtered = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)\n      raise ArgumentError, \"No --hosts match for #{hosts.join(',')}\" if filtered.empty?\n      filtered\n    end\n  end\n\n  def with_specific_hosts(hosts)\n    original_hosts, self.specific_hosts = specific_hosts, hosts\n    yield\n  ensure\n    self.specific_hosts = original_hosts","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/commander.rb#L41-L77","documentation":"Kamal::Commander#specific_roles= is called when you pass the global --roles filter (e.g. `kamal deploy --roles web,workers` or programmatic use). It filters config.roles through Kamal::Utils.filter_specific_items, which uses File.fnmatch with FNM_EXTGLOB — so filters support fnmatch patterns like 'web*' or extended globs, matched against role names. If no configured role matches any filter, the filtered list is empty and Kamal raises ArgumentError ('No --roles match for ...').","triggerScenarios":"`kamal app boot --roles web2` when config defines only web/workers; using a glob that matches nothing (`--roles job*` with no job roles); quoting issues so the filter string includes stray characters; renaming roles in deploy.yml but running old scripts with the previous names.","commonSituations":"Role renamed during config refactor while CI pipelines still pass the old --roles value; typos in role names; destination configs (deploy.staging.yml) defining a different role subset than production; glob syntax expectations differing from fnmatch semantics.","solutions":["List the roles actually defined in your config (grep `servers:` block names in config/deploy*.yml or run `kamal app details`) and correct the --roles value to match.","If you meant a pattern, ensure it is fnmatch-compatible ('web*' works; regex like 'web|workers' does not).","Update CI/alias scripts after renaming roles in deploy.yml.","If targeting a specific host instead, use --hosts with a hostname from config."],"exampleFix":"# before\n# config/deploy.yml defines servers: web: ..., workers: ...\nkamal deploy --roles webb      # typo -> No --roles match for webb\n# after\nkamal deploy --roles web\n# patterns are fnmatch-style:\nkamal deploy --roles 'w*'","handlingStrategy":"validation","validationCode":"require \"yaml\"\nconfigured = YAML.load_file(\"config/deploy.yml\")[\"servers\"].keys # role names\nrequested = %w[web workers]\nunknown = requested.reject { |r| configured.include?(r) || configured.any? { |c| File.fnmatch(r, c) } }\nabort \"no roles match #{unknown.join(',')}\" unless unknown.empty?\nsystem(\"kamal deploy --roles #{requested.join(',')}\")","typeGuard":"def roles_match?(filters, configured_roles)\n  filters.any? { |f| configured_roles.any? { |r| File.fnmatch(f, r, File::FNM_EXTGLOB) } }\nend","tryCatchPattern":"begin\n  Kamal::Commander.new.specific_roles = %w[web]\nrescue ArgumentError => e\n  raise unless e.message.include?(\"--roles\")\n  abort \"check role names in config/deploy.yml: #{e.message}\"\nend","preventionTips":["Centralize role names as a shared constant between deploy.yml and CI scripts.","Remember filters are fnmatch globs ('web*'), not regexes.","After renaming roles, grep CI configs and runbooks for old --roles values."],"tags":["kamal","roles","cli","filter","config"],"backgroundTag":"no-matching-targets","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}