puppetlabs/puppet · error · Puppet::Error

Unable to find launchd plist for job: #{label}

Error message

Unable to find launchd plist for job: #{label}

What it means

The launchd provider maps job labels to plist paths by scanning its launchd directories (make_label_to_path_map). jobsearch raises when the requested label is not in the map even after one forced refresh of the map, meaning Puppet can find no plist whose Label key matches the service name. Because launchd identifies jobs by the Label inside the plist (not the filename), a mismatch between resource name and Label is invisible to the lookup.

Source

Thrown at lib/puppet/provider/service/launchd.rb:175

  end

  # Sets a class instance variable with a hash of all launchd plist files that
  # are found on the system. The key of the hash is the job id and the value
  # is the path to the file. If a label is passed, we return the job id and
  # path for that specific job.
  def self.jobsearch(label = nil)
    by_label = make_label_to_path_map

    if label
      if by_label.has_key? label
        { label => by_label[label] }
      else
        # try refreshing the map, in case a plist has been added in the interim
        by_label = make_label_to_path_map(true)
        if by_label.has_key? label
          { label => by_label[label] }
        else
          raise Puppet::Error, "Unable to find launchd plist for job: #{label}"
        end
      end
    else
      # caller wants the whole map
      by_label
    end
  end

  # This status method lists out all currently running services.
  # This hash is returned at the end of the method.
  def self.job_list
    @job_list = Hash.new
    begin
      output = launchctl :list
      raise Puppet::Error, "launchctl list failed to return any data." if output.nil?

      output.split("\n").each do |line|
        @job_list[line.split(/\s/).last] = :running

View on GitHub (pinned to e227c27540)

Solutions

  1. Get the exact label from the system: launchctl list, or plutil -extract Label json -o - on the plist
  2. Use that exact Label string as the service resource name/title
  3. Ensure the package/file resource that installs the plist is ordered before the service resource
  4. Confirm the plist sits in a directory the provider scans (e.g. /Library/LaunchDaemons, /System/Library/LaunchDaemons)

Example fix

# before
service { 'mdns':
  ensure   => running,
  provider => 'launchd',
}

# after
service { 'com.apple.mDNSResponder':
  ensure   => running,
  provider => 'launchd',
}
Defensive patterns

Strategy: validation

Validate before calling

# the resource name must equal a real launchd Label
launchctl list | awk '{print $3}' | grep -qx "${label}" \
  || plutil -extract Label json -o - "/Library/LaunchDaemons/${label}.plist" 2>/dev/null \
  || echo "no launchd job '${label}' — check Label spelling and ordering"

Prevention

When it happens

Trigger: A service resource whose name is not the exact launchd Job Label (e.g. using a friendly name or filename when Label is com.vendor.agent); a job whose plist has not been installed yet because the shipping package runs after the service resource; plist present in a directory outside launchd_dirs; plist missing a Label key.

Common situations: Managing macOS agents on hosts where the label differs from the intuitive name (com.apple.mDNSResponder vs mdns); ordering issues where Package -> Service arrows are missing; third-party daemons dropped in /Library/LaunchDaemons with a Label typo.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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