{"record":{"id":"d3315a8ef34e052d","repo":"basecamp/kamal","slug":"accessories-name-unknown-role-accessory-conf","errorCode":null,"errorMessage":"accessories/#{name}: unknown role #{accessory_config[\"role\"]}","messagePattern":"accessories/#(.+?): unknown role #(.+?)","errorType":"validation","errorClass":"Kamal::ConfigurationError","httpStatus":null,"severity":"error","filePath":"lib/kamal/configuration/accessory.rb","lineNumber":277,"sourceCode":"    def extract_hosts_from_config_with_tag(tag)\n      if (servers_with_roles = config.raw_config.servers).is_a?(Hash)\n        servers_with_roles.flat_map do |role, servers_in_role|\n          servers_in_role.filter_map do |host|\n            host.keys.first if host.is_a?(Hash) && host.values.first.include?(tag)\n          end\n        end\n      end\n    end\n\n    def network\n      accessory_config[\"network\"] || DEFAULT_NETWORK\n    end\n\n    def ensure_valid_roles\n      if accessory_config[\"roles\"] && (missing_roles = accessory_config[\"roles\"] - config.roles.map(&:name)).any?\n        raise Kamal::ConfigurationError, \"accessories/#{name}: unknown roles #{missing_roles.join(\", \")}\"\n      elsif accessory_config[\"role\"] && !config.role(accessory_config[\"role\"])\n        raise Kamal::ConfigurationError, \"accessories/#{name}: unknown role #{accessory_config[\"role\"]}\"\n      end\n    end\nend\n","sourceCodeStart":259,"sourceCodeEnd":281,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/configuration/accessory.rb#L259-L281","documentation":"Kamal::Configuration::Accessory#ensure_valid_roles also handles the singular form: an accessory with `role:` (place this accessory on every host of that one role) is checked with config.role(name), and if no such role exists this Kamal::ConfigurationError is raised with the accessory name and the unknown role. It is the single-role counterpart to the plural `roles:` check.","triggerScenarios":"An accessory declaring `role: db` when servers define only `web`/`workers`; a role rename that missed the accessory's `role:` key; singular `role:` pointing at a name that only exists as an accessory name, not a server role.","commonSituations":"Copy-paste of accessory blocks between projects; renaming roles in servers without grepping accessories; confusion between `role:` (must match a servers role) and `host:`/`hosts:` addressing.","solutions":["Set `role:` to a key that exists under `servers:` (verify via `kamal config`).","Or switch addressing modes: use `host: 1.2.3.4` or `hosts: [...]` if the accessory should run on specific machines rather than alongside a role.","Grep the config for other references to the old name after any role rename."],"exampleFix":"# config/deploy.yml — before\nservers:\n  web:\n    - 1.2.3.4\naccessories:\n  mysql:\n    role: db\n\n# after\nservers:\n  web:\n    - 1.2.3.4\naccessories:\n  mysql:\n    host: 1.2.3.9","handlingStrategy":"validation","validationCode":"def accessory_role_valid?(raw)\n  role_names = raw[\"servers\"].is_a?(Array) ? [\"web\"] : raw[\"servers\"].keys.map(&:to_s)\n  raw[\"accessories\"].to_h.all? do |_name, cfg|\n    cfg[\"role\"].nil? || role_names.include?(cfg[\"role\"].to_s)\n  end\nend","typeGuard":null,"tryCatchPattern":"begin\n  config = Kamal::Configuration.new(create_config_files: false)\nrescue Kamal::ConfigurationError => e\n  puts \"Deploy config invalid: #{e.message}\"\n  exit 1\nend","preventionTips":["Validate role references in a config-lint step in CI.","Use host:/hosts: addressing for accessories tied to machines rather than roles.","Keep a single source of truth for role names (e.g. a YAML anchor list) reused by servers and accessories."],"tags":["kamal","accessories","roles","configuration"],"backgroundTag":"config-reference-validation-failed","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}