puppetlabs/puppet · error · Puppet::Error
Could not #{action} #{name}: #{output}
Error message
Could not #{action} #{name}: #{output} What it means
The systemd provider routes enable/disable/mask/unmask through systemctl_change_enable, which runs systemctl <action> -- <name> and converts any raised exception into Puppet::Error (the interpolated output is nil on the failure path because the assignment never completed). An ensure block always clears @cached_enabled, since post-command state is not guaranteed and a stale cache would corrupt the provider's believed state.
Source
Thrown at lib/puppet/provider/service/systemd.rb:77
true
end
when 'indirect'
Puppet.debug("Service #{@resource[:name]} is in 'indirect' state and cannot be enabled/disabled")
true
else
current == @resource[:enable]
end
end
# This helper ensures that the enable state cache is always reset
# after a systemctl enable operation. A particular service state is not guaranteed
# after such an operation, so the cache must be emptied to prevent inconsistencies
# in the provider's believed state of the service and the actual state.
# @param action [String,Symbol] One of 'enable', 'disable', 'mask' or 'unmask'
def systemctl_change_enable(action)
output = systemctl(action, '--', @resource[:name])
rescue => e
raise Puppet::Error, "Could not #{action} #{name}: #{output}", e.backtrace
ensure
@cached_enabled = nil
end
def disable
systemctl_change_enable(:disable)
end
def get_start_link_count
# Start links don't include '.service'. Just search for the service name.
if @resource[:name] =~ /\.service/
link_name = @resource[:name].split('.')[0]
else
link_name = @resource[:name]
end
Dir.glob("/etc/rc*.d/S??#{link_name}").length
endView on GitHub (pinned to e227c27540)
Solutions
- Reproduce exactly: systemctl enable -- <name> and read its stderr (usually 'Unit <name>.service does not exist')
- Order unit installation first, and add a daemon-reload exec with refreshonly between the unit file and the service resource
- Confirm the unit is visible: systemctl list-unit-files | grep <name> and systemctl cat <name>
- In containers/chroots, don't manage systemd enablement — skip the service resource or run puppet on the host, not inside the namespace
Example fix
# before
file { '/etc/systemd/system/myapp.service': source => 'puppet:///modules/app/myapp.service' }
service { 'myapp': ensure => running, enable => true }
# after
file { '/etc/systemd/system/myapp.service':
source => 'puppet:///modules/app/myapp.service',
notify => Exec['myapp-daemon-reload'],
}
exec { 'myapp-daemon-reload':
command => '/usr/bin/systemctl daemon-reload',
refreshonly => true,
}
-> service { 'myapp': ensure => running, enable => true } Defensive patterns
Strategy: validation
Validate before calling
# the unit must exist and be loaded before enable/disable/mask
systemctl cat "${name}" >/dev/null 2>&1 || echo "unit missing — install it and 'systemctl daemon-reload' first"
systemctl list-unit-files | grep -q "^${name}" || echo "unit file not registered; daemon-reload required" Try / catch
begin
provider.enable
rescue Puppet::Error => e
# output is nil on this path; run 'systemctl enable -- #{name}' by hand for the real error
warn "systemctl enable failed for #{name}: #{e.message}"
end Prevention
- Always chain unit-file installation -> daemon-reload exec (refreshonly) -> service resource
- Never run enable-management inside containers/chroots where systemd is not PID 1; scope such resources by facts
- On read-only-/etc hosts, handle unit enablement via the image/preset layer rather than systemctl at runtime
- After adding units, validate with systemctl list-unit-files in acceptance tests
When it happens
Trigger: systemctl enable/disable/mask/unmask exiting non-zero: the unit file does not exist (enable on a never-installed unit), the unit was just installed but systemd was not daemon-reloaded, running inside a container/chroot where systemd is not PID 1, or a read-only /etc (read-only bind mounts, atomic/immutable hosts).
Common situations: Missing Package/File -> Service ordering so enable runs before the unit lands; modules dropping unit files without a systemctl daemon-reload; docker exec / chroot puppet runs; /usr or /etc mounted read-only (Silverblue-style) blocking symlink creation in /etc/systemd/system.
Related errors
- Could not enable #{name}: #{output}
- Could not enable #{name}: #{detail}
- Unable to verify the SSL certificate at %{uri}
- Unknown service #{name}
- #{self.class.name} must specify a path for daemon directory
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/e972396106dd84f3.
Report an issue: GitHub.