puppetlabs/puppet · error · Puppet::Util::Windows::Error
ReplaceFile(#{target}, #{source})
Error message
ReplaceFile(#{target}, #{source}) What it means
Puppet::Util::Windows::File.replace_file calls the Win32 ReplaceFileW API to swap `target` with `source` while preserving the target's ACLs, attributes, and object ID. If ReplaceFileW returns FALSE, this Puppet::Util::Windows::Error is raised; the class appends the formatted Win32 error text (via FormatMessageW) and exposes the numeric code as e.code (from FFI.errno). The message names target and source so you can tell which side of the operation failed.
Source
Thrown at lib/puppet/util/windows/file.rb:33
def replace_file(target, source)
target_encoded = wide_string(target.to_s)
source_encoded = wide_string(source.to_s)
flags = REPLACEFILE_IGNORE_MERGE_ERRORS
backup_file = nil
result = ReplaceFileW(
target_encoded,
source_encoded,
backup_file,
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)View on GitHub (pinned to e227c27540)
Solutions
- Check e.code: 2/3 = target or source missing, 5 = access denied, 32 = file locked
- Verify both target and source exist and are on the same volume before calling
- Match or clear hidden/system/read-only attributes on the target before replacing
- Run elevated (or grant write ACL) when replacing protected files; retry once on code 32 to ride out AV scans
Example fix
// before
Puppet::Util::Windows::File.replace_file(target, source) # raises on first failure
// after
begin
Puppet::Util::Windows::File.replace_file(target, source)
rescue Puppet::Util::Windows::Error => e
Puppet.warning("replace_file failed (#{e.code}): #{e.message}")
raise if [2, 3, 5].include?(e.code) # do not retry structural failures
end Defensive patterns
Strategy: try-catch
Validate before calling
INVALID = Puppet::Util::Windows::File::INVALID_FILE_ATTRIBUTES
ok = [target, source].all? { |p| Puppet::Util::Windows::File.get_attributes(p, false) != INVALID }
raise ArgumentError, 'target/source missing or inaccessible' unless ok Try / catch
begin Puppet::Util::Windows::File.replace_file(target, source) rescue Puppet::Util::Windows::Error => e case e.code when 2, 3 then raise "replace_file: target or source missing" when 5 then raise "replace_file: access denied (elevate?)" when 32 then sleep 1; retry if (tries += 1) < 3 # AV lock else raise end end
Prevention
- Verify both paths exist and share a volume before replacing
- Align hidden/system attributes between target and replacement before the swap
- Treat code 32 (sharing violation) as transient - retry briefly before failing
When it happens
Trigger: replace_file(target, source) when target or source does not exist (code 2/3), the caller lacks write access to the target (code 5), the target has hidden/system attributes the replacement lacks, the files sit on different volumes, or another process (antivirus, indexer) holds the target open (code 32, sharing violation).
Common situations: Puppet agents running non-elevated replacing files under Program Files or system paths; targets previously marked read-only/hidden by another resource; antivirus locking files mid-swap during catalog application; long paths over 260 chars on older Windows.
Related errors
- MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})
- GetFileAttributes(#{file_name})
- Failed to set file attributes
- CreateFile(#{file_name}, #{desired_access.to_s(8)}, #{share_
- Failed to call GetLongPathName
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/220425759fd53bb4.
Report an issue: GitHub.