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

  1. Change `service:` to contain only letters, digits, hyphens, and underscores (e.g. `myapp` instead of `myapp.com`).
  2. 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.
  3. 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

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


AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21). Data as JSON: /api/errors/5238984c15fa81fa. Report an issue: GitHub.