{"record":{"id":"80a0f004ffa48249","repo":"puppetlabs/puppet","slug":"path-does-not-exist-or-is-not-a-directory","errorCode":null,"errorMessage":"%{path} does not exist or is not a directory","messagePattern":"%(.+?) does not exist or is not a directory","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/file_serving/mount/file.rb","lineNumber":57,"sourceCode":"\n  # 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?","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/file_serving/mount/file.rb#L39-L75","documentation":"Mount::File#path= validates that the target is an existing directory (FileTest.directory?) before accepting it — unless the path contains % interpolation patterns like %h/%d/%H, which are deliberately not validated (see the FIXME in the source) because the real directory depends on the requesting node.","triggerScenarios":"A `path /srv/data/conf.txt` line pointing at a regular file; a path to a directory that does not exist on the file server host; a typo'd absolute path in fileserver.conf.","commonSituations":"Confusing a file path with the directory the mount should expose; moving the served directory without updating fileserver.conf; typos or stale paths after storage migration.","solutions":["On the Puppet server, verify the target: `ls -ld /srv/data` — it must exist and be a directory","Fix the path in fileserver.conf to point at the actual directory","If you used a % pattern (%h, %d, %H) deliberately, remember this check is skipped and the failure will surface later at request time instead"],"exampleFix":"# before (fileserver.conf)\n[data]\n  path /srv/data/current.tar.gz\n  allow *\n\n# after\n[data]\n  path /srv/data\n  allow *","handlingStrategy":"validation","validationCode":"def servable_dir?(path)\n  FileTest.directory?(path)\nend\n\nraise \"not a directory: #{dir}\" unless servable_dir?(dir)","typeGuard":null,"tryCatchPattern":"begin\n  mount.path = candidate\nrescue ArgumentError => e\n  raise unless e.message.end_with?('does not exist or is not a directory')\n  candidate = ask_operator_for_real_dir(candidate)\n  retry\nend","preventionTips":["Verify mount paths on the server host before deploying config changes","Note %h/%d/%H pattern paths skip this validation and fail later","Automate creation of served directories before referencing them"],"tags":["puppet","fileserver","mount","path-validation","argumenterror"],"backgroundTag":"path-validation-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}