puppetlabs/puppet · error · Puppet::Error

Will not remove directory backup %{newfile}; use a filebucke

Error message

Will not remove directory backup %{newfile}; use a filebucket

What it means

Puppet's file resource makes local backups by copying the managed path to path + backup suffix (default 'puppet.bak') before replacing it. Before writing the new backup, perform_backup_with_backuplocal calls remove_backup to unlink the previous one. If the backup target exists and its ftype is 'directory', remove_backup raises Puppet::Error at lib/puppet/util/backups.rb:69 because Puppet refuses to recursively delete a whole directory tree just to rotate a backup; the message points at filebuckets as the supported alternative for backing up directories.

Source

Thrown at lib/puppet/util/backups.rb:69

      self.fail Puppet::Error, _("Could not back %{file} up: %{message}") % { file: file, message: detail.message }, detail
    end
  end

  def remove_backup(newfile)
    if instance_of?(Puppet::Type::File) and self[:links] != :follow
      method = :lstat
    else
      method = :stat
    end

    begin
      stat = Puppet::FileSystem.send(method, newfile)
    rescue Errno::ENOENT
      return
    end

    if stat.ftype == "directory"
      raise Puppet::Error, _("Will not remove directory backup %{newfile}; use a filebucket") % { newfile: newfile }
    end

    info _("Removing old backup of type %{file_type}") % { file_type: stat.ftype }

    begin
      Puppet::FileSystem.unlink(newfile)
    rescue => detail
      message = _("Could not remove old backup: %{detail}") % { detail: detail }
      log_exception(detail, message)
      self.fail Puppet::Error, message, detail
    end
  end

  def backup_file_with_filebucket(f)
    sum = bucket.backup(f)
    info _("Filebucketed %{f} to %{filebucket} with sum %{sum}") % { f: f, filebucket: bucket.name, sum: sum }
    sum
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Remove or rename the directory at {path}{backup} (e.g. `rm -rf /etc/motd.puppet.bak`) so the next Puppet run can recreate a regular file backup
  2. Switch the resource to filebucket backup: declare a `filebucket { 'main': server => ... }` resource and set the file's `backup` parameter to the bucket name, which is what the error message recommends
  3. Set `backup => false` on the file resource if no backup is needed at all
  4. Audit other file resources on the node for the same backup-target collision before the next agent run

Example fix

# before
file { '/etc/motd':
  ensure  => file,
  source  => 'puppet:///modules/motd/motd',
  backup  => '.bak',   # fails when /etc/motd.bak is a directory
}

# after
filebucket { 'main':
  server => 'puppet.example.com',
}
file { '/etc/motd':
  ensure  => file,
  source  => 'puppet:///modules/motd/motd',
  backup  => 'main',   # filebucket handles directories safely
}
Defensive patterns

Strategy: validation

Validate before calling

# Before letting Puppet manage the file, verify the local backup target is not a directory
path    = '/etc/motd'
suffix = '.puppet.bak'   # or the resource's backup parameter
backup_target = path + suffix

if File.exist?(backup_target) && File.ftype(backup_target) == 'directory'
  abort "Refusing to run: #{backup_target} is a directory; Puppet would fail with 'Will not remove directory backup'. Remove it or use a filebucket."
end

Try / catch

# In Ruby code driving Puppet (e.g. rake tasks, orchestration), fail gracefully instead of letting the agent run abort:
begin
  # apply the catalog / run the resource
rescue Puppet::Error => e
  if e.message.include?('Will not remove directory backup')
    target = e.message[/Will not remove directory backup ([^;]+);/, 1]
    warn "Backup target #{target} is a directory - remove it or switch the resource to a filebucket"
  else
    raise
  end
end

Prevention

When it happens

Trigger: A file resource with a local backup suffix (backup => '.bak' or the default) whose target path+backup already exists as a directory on the node: someone ran `mkdir /etc/motd.puppet.bak`, a previous run used FileUtils.cp_r (which copies directories too, see backups.rb:46) and left a directory backup that the next run now refuses to remove, or a restore/rename left a directory at exactly that name.

Common situations: Converging a node where an operator manually created a directory with the backup name; a resource that changed between file and directory content while keeping local suffix backups; leftovers from an interrupted or older-format run; path prefixes chosen so path+backup collides with an unrelated directory.

Related errors


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