puppetlabs/puppet · error · Puppet::Util::Windows::Error

MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})

Error message

MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})

What it means

Puppet::Util::Windows::File.move_file_ex wraps MoveFileExW; on FALSE it raises Puppet::Util::Windows::Error with source, target, and the flags in octal (e.g. flags=1 means MOVEFILE_REPLACE_EXISTING). The appended Win32 text and e.code identify the real cause - usually target-exists, sharing violation, or cross-device move.

Source

Thrown at lib/puppet/util/windows/file.rb:44

      flags,
      FFI::Pointer::NULL,
      FFI::Pointer::NULL
    )

    return true if result != FFI::WIN32_FALSE

    raise Puppet::Util::Windows::Error, "ReplaceFile(#{target}, #{source})"
  end
  module_function :replace_file

  def move_file_ex(source, target, flags = 0)
    result = MoveFileExW(wide_string(source.to_s),
                         wide_string(target.to_s),
                         flags)

    return true if result != FFI::WIN32_FALSE

    raise Puppet::Util::Windows::Error, "MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})"
  end
  module_function :move_file_ex

  def symlink(target, symlink)
    flags = File.directory?(target) ? 0x1 : 0x0
    result = CreateSymbolicLinkW(wide_string(symlink.to_s),
                                 wide_string(target.to_s), flags)
    return true if result != FFI::WIN32_FALSE

    raise Puppet::Util::Windows::Error, "CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})"
  end
  module_function :symlink

  def exist?(path)
    path = path.to_str if path.respond_to?(:to_str) # support WatchedFile
    path = path.to_s # support String and Pathname

    seen_paths = []

View on GitHub (pinned to e227c27540)

Solutions

  1. Pass MOVEFILE_REPLACE_EXISTING (0x1) when overwriting an existing target is intended
  2. Map e.code: 183 = target exists, 32 = locked, 17 = cross-volume, 5 = access denied, 2/3 = missing
  3. For cross-volume moves, copy + delete instead of move_file_ex
  4. Close/retry when code 32 (sharing violation) - the lock is often transient

Example fix

// before
Puppet::Util::Windows::File.move_file_ex(src, dst)  # dst exists -> ERROR_ALREADY_EXISTS

// after
MOVEFILE_REPLACE_EXISTING = 0x1
Puppet::Util::Windows::File.move_file_ex(src, dst, MOVEFILE_REPLACE_EXISTING)
Defensive patterns

Strategy: try-catch

Validate before calling

dst_exists = Puppet::Util::Windows::File.get_attributes(target, false) != Puppet::Util::Windows::File::INVALID_FILE_ATTRIBUTES
flags |= 0x1 if dst_exists  # MOVEFILE_REPLACE_EXISTING

Try / catch

begin
  Puppet::Util::Windows::File.move_file_ex(source, target, flags)
rescue Puppet::Util::Windows::Error => e
  raise "target exists, pass MOVEFILE_REPLACE_EXISTING" if e.code == 183
  raise "file locked (#{e.message})" if e.code == 32
  raise "cross-volume move: copy+delete instead" if e.code == 17
  raise
end

Prevention

When it happens

Trigger: move_file_ex(src, dst) where dst already exists and flags lacks MOVEFILE_REPLACE_EXISTING (0x1, raises ERROR_ALREADY_EXISTS/183); the file is open by another process without MOVEFILE_WRITE_THROUGH semantics (32); src and dst are on different volumes for a rename-style move (17, ERROR_NOT_SAME_DEVICE); insufficient rights (5); missing path (2/3).

Common situations: Deploy scripts moving artifacts into place where the destination from a previous run still exists; moves across drive letters or mounted volumes; files held open by editors/AV during Puppet runs; agents without modify rights on the destination folder.

Related errors


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