puppetlabs/puppet · error · Puppet::Error
Could not destroy %{name} %{request}: %{detail}
Error message
Could not destroy %{name} %{request}: %{detail} What it means
The MessagePack terminus destroy calls Puppet::FileSystem.unlink on the stored .msgpack file. Errno::ENOENT is swallowed (returns 1, emulating success), but any other error - EACCES/EPERM, EISDIR, read-only filesystem - is re-raised as Puppet::Error 'Could not destroy msgpack <key>: <original message>' with the original backtrace.
Source
Thrown at lib/puppet/indirector/msgpack.rb:36
def find(request)
load_msgpack_from_file(path(request.key), request.key)
end
def save(request)
filename = path(request.key)
FileUtils.mkdir_p(File.dirname(filename))
Puppet::FileSystem.replace_file(filename, 0o660) { |f| f.print to_msgpack(request.instance) }
rescue TypeError => detail
Puppet.log_exception(detail, _("Could not save %{name} %{request}: %{detail}") % { name: name, request: request.key, detail: detail })
end
def destroy(request)
Puppet::FileSystem.unlink(path(request.key))
rescue => detail
unless detail.is_a? Errno::ENOENT
raise Puppet::Error, _("Could not destroy %{name} %{request}: %{detail}") % { name: name, request: request.key, detail: detail }, detail.backtrace
end
1 # emulate success...
end
def search(request)
Dir.glob(path(request.key)).collect do |file|
load_msgpack_from_file(file, request.key)
end
end
# Return the path to a given node's file.
def path(name, ext = '.msgpack')
if name =~ Puppet::Indirector::BadNameRegexp then
Puppet.crit(_("directory traversal detected in %{indirection}: %{name}") % { indirection: self.class, name: name.inspect })
raise ArgumentError, _("invalid key")
end
View on GitHub (pinned to e227c27540)
Solutions
- Read the <detail> suffix; it identifies the real errno.
- chown -R <serviceuser>:<servicegroup> the datadir (Puppet[:server_datadir] / Puppet[:client_datadir]) so the service user can unlink.
- Remount writable or move the datadir off the read-only filesystem.
- Check SELinux audit logs and restorecon when labels are the cause.
Example fix
# before # Could not destroy msgpack node1.example.com: Read-only file system @ unlink_internal # after: relocate the datadir to a writable volume # puppet.conf: [server] server_datadir = /var/lib/puppet/server_data systemctl restart puppetserver
Defensive patterns
Strategy: try-catch
Validate before calling
path = File.join(store_dir, indirection_name, key + '.msgpack') raise ArgumentError, 'not removable by this user' unless File.writable?(File.dirname(path)) && (File.writable?(path) || !File.exist?(path))
Try / catch
begin
indirection.destroy(key)
rescue Puppet::Error => e
Puppet.err('destroy failed: ' + e.message) # operator follow-up: fix ownership/mount
end Prevention
- Keep msgpack datadir ownership under the service user.
- Avoid read-only mounts for datadirs.
- Include destroy operations in smoke tests.
When it happens
Trigger: Destroying an entry in a msgpack-backed indirection store when the datadir file is owned by another user, the filesystem is read-only, or the path is a directory.
Common situations: Service/datadir ownership drift after upgrades or container rebuilds; mixed root/service-user runs; read-only persistent volumes; SELinux label changes on migrated volumes.
Related errors
- Could not destroy %{json} %{request}: %{detail}
- Could not read JSON data for %{name} %{key}: %{detail}
- Could not back up %{file}: %{detail}
- %{path} is not readable
- invalid key
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/587bc04eefb4d819.
Report an issue: GitHub.