puppetlabs/puppet · error · Puppet::Error
Could not remove existing file
Error message
Could not remove existing file
What it means
Inside mklink, Puppet first calls remove_existing(target) to clear whatever occupies the link path, then verifies with Puppet::FileSystem.exist? that the path is actually gone. If the entry survived removal (permissions, read-only attributes, open handles, non-empty directory), it raises 'Could not remove existing file' rather than letting symlink(2) fail obscurely.
Source
Thrown at lib/puppet/type/file/target.rb:45
newvalue(/./) do
@resource[:ensure] = :link unless @resource.should(:ensure)
# Only call mklink if ensure didn't call us in the first place.
currentensure = @resource.property(:ensure).retrieve
mklink if @resource.property(:ensure).safe_insync?(currentensure)
end
# Create our link.
def mklink
raise Puppet::Error, "Cannot symlink on this platform version" unless provider.feature?(:manages_symlinks)
target = should
# Clean up any existing objects. The argument is just for logging,
# it doesn't determine what's removed.
@resource.remove_existing(target)
raise Puppet::Error, "Could not remove existing file" if Puppet::FileSystem.exist?(@resource[:path])
Puppet::Util::SUIDManager.asuser(@resource.asuser) do
mode = @resource.should(:mode)
if mode
Puppet::Util.withumask(0o00) do
Puppet::FileSystem.symlink(target, @resource[:path])
end
else
Puppet::FileSystem.symlink(target, @resource[:path])
end
end
@resource.send(:property_fix)
:link_created
end
def insync?(currentvalue)View on GitHub (pinned to e227c27540)
Solutions
- Inspect the path: ls -ld (POSIX) or handle.exe (Windows) and clear the entry manually.
- Manage the conflicting object in Puppet: a file resource with ensure => absent ordered before the link.
- On Windows, remove read-only attributes, close locking processes, and run elevated.
- If the entry is a directory, remove it (or manage its removal) before creating the link.
Example fix
// before: /opt/app/current occupied by a locked file
file { '/opt/app/current':
ensure => link,
target => '/opt/app/releases/2026.08',
}
// after: manage removal first, then the link
file { '/opt/app/current': ensure => absent }
->
file { '/opt/app/current':
ensure => link,
target => '/opt/app/releases/2026.08',
} Defensive patterns
Strategy: validation
Validate before calling
# Ruby pre-flight before creating a link
if Puppet::FileSystem.exist?(link_path)
st = File.lstat(link_path)
fail("cannot clear #{link_path} (#{st.ftype}) — remove it or manage ensure => absent first") unless File.writable?(File.dirname(link_path))
end Try / catch
rescue Puppet::Error on /Could not remove existing file/; lstat the path, close locks / clear read-only attributes / pre-remove the entry, then re-run the agent — creation is idempotent.
Prevention
- Manage the old object explicitly (ensure => absent) before introducing the link.
- Check open handles on Windows (handle.exe, Resource Monitor).
- Ensure the agent user can write the containing directory.
- Keep AV/backup agents from recreating the path mid-run.
When it happens
Trigger: `ensure => link` onto a path occupied by a file the agent cannot delete (EACCES/EPERM); a Windows file with the read-only attribute or an open handle; the existing entry being a non-empty directory; another process re-creating the path between removal and the check.
Common situations: Windows agents hitting locked/read-only files (AV scanners, backup agents); agent running non-root over root-owned entries; deployment layouts where 'current' exists as a directory from a previous release.
Related errors
- Could not back up; will not remove
- Could not read #{ftype} #{resource.title}: #{detail}
- Cannot symlink on this platform version
- Could not back up %{file}: %{detail}
- %{path} is not readable
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/cef720bf1bb3e487.
Report an issue: GitHub.