{"record":{"id":"146d71be07f6c2a0","repo":"puppetlabs/puppet","slug":"retrieving-nfs-reparse-point-data-is-unsupported","errorCode":null,"errorMessage":"Retrieving NFS reparse point data is unsupported","messagePattern":"Retrieving NFS reparse point data is unsupported","errorType":"exception","errorClass":"Puppet::Util::Windows::Error","httpStatus":null,"severity":"warning","filePath":"lib/puppet/util/windows/file.rb","lineNumber":154,"sourceCode":"\n    raise Puppet::Util::Windows::Error, \"CreateFile(#{file_name}, #{desired_access.to_s(8)}, #{share_mode.to_s(8)}, \" \\\n                                        \"#{security_attributes}, #{creation_disposition.to_s(8)}, \" \\\n                                        \"#{flags_and_attributes.to_s(8)}, #{template_file_handle})\"\n  end\n\n  def self.get_reparse_point_data(handle, &block)\n    # must be multiple of 1024, min 10240\n    FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr|\n      device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)\n\n      reparse_tag = reparse_data_buffer_ptr.read_win32_ulong\n      buffer_type = case reparse_tag\n                    when IO_REPARSE_TAG_SYMLINK\n                      SYMLINK_REPARSE_DATA_BUFFER\n                    when IO_REPARSE_TAG_MOUNT_POINT\n                      MOUNT_POINT_REPARSE_DATA_BUFFER\n                    when IO_REPARSE_TAG_NFS\n                      raise Puppet::Util::Windows::Error, \"Retrieving NFS reparse point data is unsupported\"\n                    else\n                      raise Puppet::Util::Windows::Error, \"DeviceIoControl(#{handle}, \" \\\n                                                          \"FSCTL_GET_REPARSE_POINT) returned unknown tag 0x#{reparse_tag.to_s(16).upcase}\"\n                    end\n\n      yield buffer_type.new(reparse_data_buffer_ptr)\n    end\n\n    # underlying struct MemoryPointer has been cleaned up by this point, nothing to return\n    nil\n  end\n\n  def self.get_reparse_point_tag(handle)\n    reparse_tag = nil\n\n    # must be multiple of 1024, min 10240\n    FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr|\n      device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/windows/file.rb#L136-L172","documentation":"Inside get_reparse_point_data, after DeviceIoControl(FSCTL_GET_REPARSE_POINT) returns the tag, a tag of IO_REPARSE_TAG_NFS raises this Puppet::Util::Windows::Error. NFS reparse points (files accessed through Windows' Services-for-NFS / WSL network filesystems) carry symlink data in an undocumented layout, and Puppet's reader only understands SYMLINK and MOUNT_POINT buffers - so it refuses rather than misparse.","triggerScenarios":"Calling get_reparse_point_data (directly or via symlink inspection like readlink/get_stat) on a file whose reparse tag is IO_REPARSE_TAG_NFS - i.e. a symlink created on an NFS share mounted through Windows NFS client.","commonSituations":"Site data served from NFS and consumed on Windows agents; mixed Unix/Windows shops where Unix masters create symlinks that land on NFS mounts; CI against NFS-backed test fixtures.","solutions":["Rescue this specific error and treat the entry as an opaque/regular file","Pre-check the tag with get_reparse_point_tag(handle) and skip NFS-tagged entries","Serve the affected files from a native Windows filesystem (SMB/NTFS) instead of NFS","Avoid managing NFS-symlinked paths with resources that dereference links"],"exampleFix":"// before\nPuppet::Util::Windows::File.get_reparse_point_data(handle) { |buf| ... }  # NFS tag -> raise\n\n// after\ntag = Puppet::Util::Windows::File.get_reparse_point_tag(handle)\nif tag == Puppet::Util::Windows::File::IO_REPARSE_TAG_NFS\n  Puppet.debug(\"skipping NFS reparse point\")\nelse\n  Puppet::Util::Windows::File.get_reparse_point_data(handle) { |buf| ... }\nend","handlingStrategy":"validation","validationCode":"tag = Puppet::Util::Windows::File.get_reparse_point_tag(handle)\nif tag == Puppet::Util::Windows::File::IO_REPARSE_TAG_NFS\n  Puppet.debug(\"#{path}: NFS reparse point - skipping\")\n  return nil\nend\nPuppet::Util::Windows::File.get_reparse_point_data(handle) { |buf| process(buf) }","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::Util::Windows::File.get_reparse_point_data(handle) { |buf| process(buf) }\nrescue Puppet::Util::Windows::Error => e\n  raise unless e.message.include?('NFS reparse point')\n  # NFS layout is unreadable here - treat as plain file\nend","preventionTips":["Check the reparse tag before decoding the buffer","Avoid managing NFS-hosted symlinks with link-following resources","Serve Windows-managed files from SMB/NTFS rather than NFS mounts"],"tags":["windows","reparse-point","nfs","symlink","ffi","puppet"],"backgroundTag":"unsupported-reparse-point","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}