basecamp/kamal · error · Kamal::ConfigurationError

Must retain at least 1 container

Error message

Must retain at least 1 container

What it means

Kamal::Configuration#ensure_retain_containers_valid rejects configs where fewer than one old container would be kept. retain_containers (default 5) controls how many old app container versions remain on each host after deploys so you can roll back; zero or negative values would leave no rollback target, so Kamal refuses the configuration.

Source

Thrown at lib/kamal/configuration.rb:378

      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

    def ensure_no_traefik_reboot_hooks
      hooks = %w[ pre-traefik-reboot post-traefik-reboot ].select { |hook_file| File.exist?(File.join(hooks_path, hook_file)) }

      if hooks.any?
        raise Kamal::ConfigurationError, "Found #{hooks.join(", ")}, these should be renamed to (pre|post)-proxy-reboot"
      end

      true
    end

    def ensure_one_host_for_ssl_roles
      roles.each(&:ensure_one_host_for_ssl)

      true

View on GitHub (pinned to eee0083b38)

Solutions

  1. Set `retain_containers` to at least 1 (e.g. `retain_containers: 2`) — small values still bound disk usage.
  2. If disk pressure is the motive, use a modest value like 2-3 rather than 0, since rollback requires a retained container.
  3. If ERB computes the value, clamp it: `[ ENV["RETAIN"].to_i, 1 ].max`.

Example fix

# config/deploy.yml — before
retain_containers: 0

# after
retain_containers: 2
Defensive patterns

Strategy: validation

Validate before calling

def valid_retain_containers?(raw)
  v = raw["retain_containers"]
  v.nil? || (v.is_a?(Integer) && v >= 1)
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 `retain_containers: 0` in config/deploy.yml (often to save disk space); computing retain_containers from ERB/ENV that resolves to 0 or a negative number; a typo like `retain_containers: -1`.

Common situations: Aggressive disk cleanup on small VPS hosts; per-environment overrides where staging sets 0; templated values from a variables file defaulting incorrectly.

Related errors


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