puppetlabs/puppet · error · Puppet::Error

Could not read JSON data for %{name} %{key}: %{detail}

Error message

Could not read JSON data for %{name} %{key}: %{detail}

What it means

load_json_from_file reads the stored .json file in binary mode; Errno::ENOENT returns nil (a cache miss), but any other failure - EACCES, EISDIR, EMFILE, EIO - is wrapped as Puppet::Error 'Could not read JSON data for <indirection> <key>: <detail>' with the original backtrace.

Source

Thrown at lib/puppet/indirector/json.rb:65

    base = data_dir
    File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
  end

  private

  def data_dir
    Puppet.run_mode.server? ? Puppet[:server_datadir] : Puppet[:client_datadir]
  end

  def load_json_from_file(file, key)
    json = nil

    begin
      json = Puppet::FileSystem.read(file, :encoding => Encoding::BINARY)
    rescue Errno::ENOENT
      return nil
    rescue => detail
      raise Puppet::Error, _("Could not read JSON data for %{name} %{key}: %{detail}") % { name: indirection.name, key: key, detail: detail }, detail.backtrace
    end

    begin
      from_json(json)
    rescue => detail
      raise Puppet::Error, _("Could not parse JSON data for %{name} %{key}: %{detail}") % { name: indirection.name, key: key, detail: detail }, detail.backtrace
    end
  end

  def from_json(text)
    model.convert_from('json', text.force_encoding(Encoding::UTF_8))
  end

  def to_json(object)
    object.render('json')
  end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Read the <detail> suffix to identify the errno, then reproduce as the service user (sudo -u puppet cat <file>).
  2. chown/chmod the file and its parent directory to the puppet service user.
  3. Remove or rename the directory sitting at the file path so Puppet can recreate the file.
  4. Raise ulimit / fix fd leaks if the detail says 'too many open files'.

Example fix

# before
# Could not read JSON data for node node1.example.com: Permission denied @ rb_sysopen

# after
chown puppet:puppet /opt/puppetlabs/server/data/puppet/node/node1.example.com.json
chmod 660 /opt/puppetlabs/server/data/puppet/node/node1.example.com.json
Defensive patterns

Strategy: try-catch

Validate before calling

file = store_path_for(key)
raise ArgumentError, 'unreadable store file' unless File.readable?(file)
indirection.find(key)

Try / catch

begin
  Puppet::Node.indirection.find(key)
rescue Puppet::Error => e
  Puppet.err(e.message)
  nil
end

Prevention

When it happens

Trigger: find/search on a json-backed indirection when the stored file exists but is unreadable by the service user, the path has been replaced by a directory, or the process ran out of file descriptors.

Common situations: Datadir files left 600/root after a restore or manual copy; backup jobs recreating paths as directories; long-running masters hitting fd limits; SELinux context changes.

Related errors


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