puppetlabs/puppet · error · Puppet::ExecutionFailure

Execution of '%{str}' returned %{exit_status}: %{output}

Error message

Execution of '%{str}' returned %{exit_status}: %{output}

What it means

On Windows, Puppet::Util.execute launches the process via the Win32 API and collects its exit status; when failonfail is true and the status is non-zero it raises Puppet::ExecutionFailure including the command string, the numeric exit status, and the stripped stdout/stderr output. It is the Windows counterpart of the POSIX ExecutionFailure and carries the same meaning: the external command failed.

Source

Thrown at lib/puppet/util/execution.rb:312

            rescue
              nil
            end
          }
          exit_status = Puppet::Util::Windows::Process.wait_process(process_info.process_handle)

          # read output in if required
          unless options[:squelch]
            output = wait_for_output(stdout)
            Puppet.warning _("Could not get output") unless output
          end
        ensure
          FFI::WIN32.CloseHandle(process_info.process_handle)
          FFI::WIN32.CloseHandle(process_info.thread_handle)
        end
      end

      if options[:failonfail] and exit_status != 0
        raise Puppet::ExecutionFailure, _("Execution of '%{str}' returned %{exit_status}: %{output}") % { str: command_str, exit_status: exit_status, output: output.strip }
      end
    ensure
      # Make sure all handles are closed in case an exception was thrown attempting to execute.
      [stdin, stdout, stderr].each { |io|
        begin
          io.close
        rescue
          nil
        end
      }
      unless options[:squelch]
        # if we opened a pipe, we need to clean it up.
        reader.close if reader
        stdout.close! if stdout && Puppet::Util::Platform.windows?
      end
    end

    Puppet::Util::Execution::ProcessOutput.new(output || '', exit_status)

View on GitHub (pinned to e227c27540)

Solutions

  1. Re-run the exact command in the same shell as the same account and check %ERRORLEVEL% to see the real failure
  2. Rescue Puppet::ExecutionFailure and branch on the exit code embedded in the message text
  3. Pass failonfail: false when non-zero exits are an expected outcome and inspect the output
  4. Run the agent/service under an account with the privileges the command needs

Example fix

# before
Puppet::Util.execute('net localgroup Developers alice /add')
# => Puppet::ExecutionFailure: Execution of 'net localgroup ...' returned 2: The account already exists ...

# after
begin
  Puppet::Util.execute('net localgroup Developers alice /add')
rescue Puppet::ExecutionFailure => e
  code = e.message[/returned (\d+):/, 1]&.to_i
  raise unless [0, 1378].include?(code) # 1378 = already a member
end
Defensive patterns

Strategy: try-catch

Validate before calling

unless Puppet::Util.which('net.exe')
  raise ArgumentError, 'net.exe not found on PATH'
end

Try / catch

begin
  Puppet::Util.execute(cmd)
rescue Puppet::ExecutionFailure => e
  code = e.message[/returned (\d+):/, 1]&.to_i
  raise unless [0, 2].include?(code)
end

Prevention

When it happens

Trigger: Running a failing .bat/.exe/PowerShell command through Puppet on Windows with the default failonfail: true — net.exe returning 2, msiexec returning 1603, or a PowerShell one-liner exiting with a script-set code.

Common situations: Windows package installs (msiexec error codes), net/user commands failing due to missing privileges, batch scripts that exit non-zero by design, and running under a restricted service account.

Related errors


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