basecamp/kamal · error · Kamal::ConfigurationError
Service name can only include alphanumeric characters, hyphe
Error message
Service name can only include alphanumeric characters, hyphens, and underscores
What it means
Kamal::Configuration#ensure_valid_service_name enforces that the `service:` value matches /^[a-z0-9_-]+$/i — alphanumeric characters, hyphens, and underscores only. The service name is used to derive hostnames, container names, and Docker resource labels, so characters like dots, spaces, or slashes would break downstream Docker/Traefik commands. Any deviation aborts configuration loading.
Source
Thrown at lib/kamal/configuration.rb:364
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
end
def ensure_valid_kamal_version
if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Kamal::VERSION)
raise Kamal::ConfigurationError, "Current version is #{Kamal::VERSION}, minimum required is #{minimum_version}"
end
true
end
def ensure_retain_containers_valid
raise Kamal::ConfigurationError, "Must retain at least 1 container" if retain_containers < 1
true
end
View on GitHub (pinned to eee0083b38)
Solutions
- Change `service:` to contain only letters, digits, hyphens, and underscores (e.g. `myapp` instead of `myapp.com`).
- If the name comes from ERB/ENV, sanitize it in the template (`ENV["APP_NAME"].to_s.gsub(/[^a-zA-Z0-9_-]/, "-")`) or fix the source value.
- Note that changing the service name changes derived hostnames and labels — clean up old containers and volumes from the previous name after migrating.
Example fix
# config/deploy.yml — before service: myapp.example.com # after service: myapp
Defensive patterns
Strategy: validation
Validate before calling
VALID_SERVICE = /\A[a-z0-9_-]+\z/i def valid_service_name?(name) = VALID_SERVICE.match?(name.to_s)
Type guard
def kamal_service_name?(value)
value.is_a?(String) && value.match?(%r{\A[a-zA-Z0-9_-]+\z})
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
- Never derive service from a domain or registry path; pick a short slug once.
- Sanitize ENV-sourced names in ERB: `ENV["APP_NAME"].to_s.gsub(/[^a-zA-Z0-9_-]/, "-")`.
- Remember changing the service name changes derived hostnames and labels — plan cleanup.
When it happens
Trigger: Setting `service: myapp.com` or `service: my app` in config/deploy.yml; deriving the service name from an ENV var or ERB expression containing a dot or slash (e.g. a git remote or repo path); copying the service value from a container registry path like `team/myapp`.
Common situations: Using the domain or repo path as the service name; ERB interpolating `ENV["APP_NAME"]` that unexpectedly contains whitespace; renaming a service to match a FQDN for cosmetic reasons.
Related errors
- Missing required configuration for #{key}
- Invalid hooks_output '#{level}'#{context}, must be one of: #
- Invalid cache type: #{@options["cache"]["type"]}
- #{error_context}#{message}
- You must specify a destination
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/5238984c15fa81fa.
Report an issue: GitHub.