{"record":{"id":"97573b9da94dbe06","repo":"puppetlabs/puppet","slug":"path-is-not-readable","errorCode":null,"errorMessage":"%{path} is not readable","messagePattern":"%(.+?) is not readable","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/file_serving/mount/file.rb","lineNumber":58,"sourceCode":"  # Return the path as appropriate, expanding as necessary.\n  def path(node = nil)\n    if expandable?\n      expand(@path, node)\n    else\n      @path\n    end\n  end\n\n  # Set the path.\n  def path=(path)\n    # FIXME: For now, just don't validate paths with replacement\n    # patterns in them.\n    if path =~ /%./\n      # Mark that we're expandable.\n      @expandable = true\n    else\n      raise ArgumentError, _(\"%{path} does not exist or is not a directory\") % { path: path } unless FileTest.directory?(path)\n      raise ArgumentError, _(\"%{path} is not readable\") % { path: path } unless FileTest.readable?(path)\n\n      @expandable = false\n    end\n    @path = path\n  end\n\n  def search(path, request)\n    path = complete_path(path, request.node)\n    return nil unless path\n\n    [path]\n  end\n\n  # Verify our configuration is valid.  This should really check to\n  # make sure at least someone will be allowed, but, eh.\n  def validate\n    raise ArgumentError, _(\"Mounts without paths are not usable\") if @path.nil?\n  end","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/file_serving/mount/file.rb#L40-L76","documentation":"The second check in Mount::File#path=: after confirming the directory exists, FileTest.readable? must pass for the process loading the config. A missing execute/search or read permission on the served directory makes the mount unusable and raises ArgumentError.","triggerScenarios":"The served directory is owned root:0600 (or lacks o+x) while puppet/puppetserver runs as the `puppet` user; SELinux or AppArmor denials on the path; a mount path on storage with restrictive ACLs.","commonSituations":"Directories created by root scripts with umask 077; puppetserver running as a dedicated user after previously running as root; SELinux enforcing on EL systems with non-standard content paths.","solutions":["Identify the user the file server runs as, then grant traversal/read: `chmod o+rx /srv/data` or `chown -R puppet: /srv/data` as appropriate","For SELinux, restore the correct context (restorecon / semanage fcontext) on the served path","Verify as the service user: `sudo -u puppet test -r /srv/data && echo ok`"],"exampleFix":"# before\n# /srv/data owned root:600, puppetserver runs as 'puppet'\n[data]\n  path /srv/data\n\n# after (shell)\nsudo chown -R puppet: /srv/data\nsudo chmod -R u+rX /srv/data\n# fileserver.conf stays the same","handlingStrategy":"validation","validationCode":"def readable_by?(user, dir)\n  system(\"sudo -u #{user} test -r #{Shellwords.escape(dir)}\")\nend\n\nfail \"#{dir} not readable by puppet\" unless readable_by?('puppet', dir)","typeGuard":null,"tryCatchPattern":"begin\n  mount.path = dir\nrescue ArgumentError => e\n  raise unless e.message.end_with?('is not readable')\n  raise \"fix permissions on #{dir} for the service user, then redeploy\"\nend","preventionTips":["Check readability as the puppet/puppetserver service user, not as root","Standardize ownership (puppet:puppet) for served trees","On SELinux hosts, label non-standard content paths correctly"],"tags":["puppet","fileserver","mount","permissions","argumenterror"],"backgroundTag":"permission-denied","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}