Search code examples
pythonsftppysftp

Python pysftp.put raises "No such file" exception although file is uploaded


I am using pysftp to connect to a server and upload a file.

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
self.sftp = pysftp.Connection(host=self.serverConnectionAuth['host'], port=self.serverConnectionAuth['port'],
                              username=self.serverConnectionAuth['username'], password=self.serverConnectionAuth['password'], 
                              cnopts=cnopts)
self.sftp.put(localpath=self.filepath+filename, remotepath=filename)

Although it works correctly most of the times, sometimes it raises the exception attached bellow. The file is read and processed by another program running on the server, so I can see that, even at these times, the file is indeed uploaded and is not corrupted.

  File "E:\Anaconda\envs\py35\lib\site-packages\pysftp\__init__.py", line 364, in put
    confirm=confirm)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 727, in put
    return self.putfo(fl, remotepath, file_size, callback, confirm)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 689, in putfo
    s = self.stat(remotepath)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 460, in stat
    t, msg = self._request(CMD_STAT, path)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 780, in _request
    return self._read_response(num)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 832, in _read_response
    self._convert_status(msg)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 861, in _convert_status
    raise IOError(errno.ENOENT, text)
FileNotFoundError: [Errno 2] No such file

How can I prevent this exception?


Solution

  • From the described behaviour, I assume that the file is removed very shortly after it is uploaded by some server-side process.

    By default pysftp.Connection.put verifies the upload by checking a size of the target file. If the server-side processes manages to remove the file too fast, reading the file size would fail.

    You can disable the post-upload check by setting confirm parameter to False:

    self.sftp.put(localpath=self.filepath+filename, remotepath=filename, confirm=False)
    

    I believe the check is redundant anyway, see
    How to perform checksums during a SFTP file transfer for data integrity?


    For a similar question about Paramiko (which pysftp uses internally), see:
    Paramiko put method throws "[Errno 2] File not found" if SFTP server has trigger to automatically move file upon upload

    And actually, you should use Paramiko directly, as pysftp is a dead project. See pysftp vs. Paramiko.