puppetlabs/puppet · error · Puppet::Error

The service must be in one of the %{valid_initial_states} st

Error message

The service must be in one of the %{valid_initial_states} states to perform this transition. It is currently in the %{current_state} state.

What it means

Raised inside transition_service_state when the service's current state is not among the valid initial states for the requested transition. start() only accepts STOPPED, STOP_PENDING, and START_PENDING; stop() accepts everything except STOPPED; resume() requires PAUSED/PAUSE_PENDING. So, for example, starting a paused service or resuming a running one trips this before any control call is made.

Source

Thrown at lib/puppet/util/windows/service.rb:362

        open_service(service_name, SC_MANAGER_CONNECT, service_access) do |service|
          query_status(service) do |status|
            initial_state = status[:dwCurrentState]
            # If the service is already in the final_state, then
            # no further work needs to be done
            if initial_state == final_state
              Puppet.debug _("The service is already in the %{final_state} state. No further work needs to be done.") % { final_state: SERVICE_STATES[final_state] }

              next
            end

            # Check that initial_state corresponds to a valid
            # initial state
            unless valid_initial_states.include?(initial_state)
              valid_initial_states_str = valid_initial_states.map do |state|
                SERVICE_STATES[state]
              end.join(", ")

              raise Puppet::Error, _("The service must be in one of the %{valid_initial_states} states to perform this transition. It is currently in the %{current_state} state.") % { valid_initial_states: valid_initial_states_str, current_state: SERVICE_STATES[initial_state] }
            end

            # Check if there's a pending transition to the final_state. If so, then wait for
            # that transition to finish.
            possible_pending_states = FINAL_STATES.keys.select do |pending_state|
              # SERVICE_RUNNING has two pending states, SERVICE_START_PENDING and
              # SERVICE_CONTINUE_PENDING. That is why we need the #select here
              FINAL_STATES[pending_state] == final_state
            end
            if possible_pending_states.include?(initial_state)
              Puppet.debug _("There is already a pending transition to the %{final_state} state for the %{service_name} service.") % { final_state: SERVICE_STATES[final_state], service_name: service_name }
              wait_on_pending_state(service, initial_state, timeout)

              next
            end

            # If we are in an unsafe pending state like SERVICE_START_PENDING
            # or SERVICE_STOP_PENDING, then we want to wait for that pending

View on GitHub (pinned to e227c27540)

Solutions

  1. Query Puppet::Util::Windows::Service.service_state(service_name) and branch before calling start/stop/resume
  2. For start, first resume-or-stop a paused service (or set it to stopped) so it lands in an accepted initial state
  3. Re-fetch state and retry once on this specific error, since state may have changed between check and call
  4. Reduce concurrent external service control (monitoring restarts) while the code transitions services

Example fix

// before
Puppet::Util::Windows::Service.start('myservice')

# after
state = Puppet::Util::Windows::Service.service_state('myservice')
if state == :SERVICE_PAUSED
  # paused is not a valid initial state for start
  Puppet::Util::Windows::Service.stop('myservice')
end
Puppet::Util::Windows::Service.start('myservice')
Defensive patterns

Strategy: validation

Validate before calling

state = Puppet::Util::Windows::Service.service_state(name)
VALID_FOR_START = [:SERVICE_STOPPED, :SERVICE_STOP_PENDING, :SERVICE_START_PENDING].freeze
unless VALID_FOR_START.include?(state)
  Puppet::Util::Windows::Service.stop(name) if state == :SERVICE_PAUSED
end
Puppet::Util::Windows::Service.start(name)

Type guard

def startable_state?(state)
  [:SERVICE_STOPPED, :SERVICE_STOP_PENDING, :SERVICE_START_PENDING].include?(state)
end

Try / catch

begin
  Puppet::Util::Windows::Service.start(name)
rescue Puppet::Error => e
  retry if e.message.include?('must be in one of the') # state changed between check and call
  raise
end

Prevention

When it happens

Trigger: Calling start while the service is SERVICE_PAUSED or SERVICE_PAUSE_PENDING; calling resume on a service that is SERVICE_RUNNING; calling stop on an already-stopped service raced between the exists/state check and the transition; any transition attempted from a state the API's valid_initial_states list excludes.

Common situations: Idempotency code that assumes 'running' without checking state first; races where another admin or monitor changes service state concurrently; manifests that both stop and start a service in the same run while it is mid-transition.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/3a3542e6b1618455. Report an issue: GitHub.