puppetlabs/puppet · error · Puppet::Error

Do not directly call the init script for '#{@resource[:name]

Error message

Do not directly call the init script for '#{@resource[:name]}'; use 'service' instead

What it means

The redhat provider overrides initscript to unconditionally raise, deliberately blocking any code path that would execute /etc/init.d/<name> directly. All its operations go through /sbin/service instead (statuscmd/restartcmd/startcmd build command(:service) arrays); the guard exists so subclasses or base-class fallbacks that resolve the script path cannot silently bypass the service wrapper.

Source

Thrown at lib/puppet/provider/service/redhat.rb:56

    # For Suse OS family, chkconfig returns 0 even if the service is disabled or non-existent
    # Therefore, check the output for '<name>  on' (or '<name>  B for boot services)
    # to see if it is enabled
    return :false unless Puppet.runtime[:facter].value('os.family') != 'Suse' || output =~ /^#{name}\s+(on|B)$/

    :true
  end

  # Don't support them specifying runlevels; always use the runlevels
  # in the init scripts.
  def enable
    chkconfig("--add", @resource[:name])
    chkconfig(@resource[:name], :on)
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, "Could not enable #{name}: #{detail}", detail.backtrace
  end

  def initscript
    raise Puppet::Error, "Do not directly call the init script for '#{@resource[:name]}'; use 'service' instead"
  end

  # use hasstatus=>true when its set for the provider.
  def statuscmd
    ((@resource.provider.get(:hasstatus) == true) || (@resource[:hasstatus] == :true)) && [command(:service), @resource[:name], "status"]
  end

  def restartcmd
    (@resource[:hasrestart] == :true) && [command(:service), @resource[:name], "restart"]
  end

  def startcmd
    [command(:service), @resource[:name], "start"]
  end

  def stopcmd
    [command(:service), @resource[:name], "stop"]
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Do not call initscript on this provider; use command(:service) based commands or the provider's own startcmd/stopcmd/statuscmd
  2. In manifests, leave hasstatus/hasrestart unset or true on redhat-family services so the /sbin/service paths are used
  3. For custom logic, invoke /sbin/service <name> <action> (or systemctl on EL7+) explicitly instead of the script path
  4. If you truly need the script path, read File.join('/etc/init.d', name) yourself rather than the provider API

Example fix

# before
def my_start
  [initscript, :start] # raises on the redhat provider
end

# after
def my_start
  [command(:service), @resource[:name], 'start']
end
Defensive patterns

Strategy: validation

Validate before calling

# in the profile: refuse attribute combos that fall back to init-script paths on redhat
if $provider == 'redhat' and ($hasstatus == false or $hasrestart == false) {
  fail("${title}: redhat provider forbids direct init script use; keep hasstatus/hasrestart enabled")
}

Prevention

When it happens

Trigger: Anything invoking provider.initscript on the redhat provider: custom providers inheriting from it that call super-side helpers, code calling provider.initscript directly (e.g. to inspect or execute the script), or resource attribute combinations that drop the provider back to base-class command resolution instead of the service-command paths.

Common situations: Module code or Bolt tasks poking provider.initscript for discovery; setting hasstatus => false / omitting the attributes such that base-class status/start paths would need the raw script; third-party providers subclassing Provider::Service::Redhat with old assumptions.

Related errors


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