jschneier / django-storages

https://django-storages.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
2.76k stars 863 forks source link

SFTP - RecursionError being raised when connection is refused #975

Closed strikaco closed 1 year ago

strikaco commented 3 years ago

Spent all day trying to debug this one, heh.

The SFTP client gets caught in a tailspin over a supposed RecursionError-- but the root cause turned out to be that the remote host was unavailable.

There must be a better way to handle this circumstance; this error was certainly misleading :)

  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 130, in _save
    self._mkdir(dirname)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 115, in _mkdir
    self._mkdir(parent)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 115, in _mkdir
    self._mkdir(parent)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 115, in _mkdir
    self._mkdir(parent)
  [Previous line repeated 965 more times]
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 114, in _mkdir
    if not self.exists(parent):
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 151, in exists
    self.sftp.stat(self._remote_path(name))
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 87, in sftp
    self._connect()
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/storages/backends/sftpstorage.py", line 61, in _connect
    self._ssh.load_host_keys(known_host_file)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/paramiko/client.py", line 127, in load_host_keys
    self._host_keys.load(filename)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/paramiko/hostkeys.py", line 101, in load
    e = HostKeyEntry.from_line(line, lineno)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/paramiko/hostkeys.py", line 364, in from_line
    key = ECDSAKey(data=decodebytes(key), validate_point=False)
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/paramiko/ecdsakey.py", line 164, in __init__
    self.ecdsa_curve.curve_class(), pointinfo
  File "/home/ubuntu/workspace/E37/lib/python3.7/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py", line 159, in from_encoded_point
    if not isinstance(curve, EllipticCurve):
  File "/usr/lib/python3.7/abc.py", line 139, in __instancecheck__
    return _abc_instancecheck(cls, instance)
  File "/usr/lib/python3.7/abc.py", line 143, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
RecursionError: maximum recursion depth exceeded in comparison
jschneier commented 3 years ago

Agreed. I would assume that the .exists() would blow up but perhaps the issue is OSError it too wide. What are your thoughts on that?

strikaco commented 3 years ago

Re-reading that stack trace, Paramiko may be best blamed for the lack of coherence.

I don't know what other conditions might yield the same error so I hesitate to recommend capturing and rewrapping a generic error like this as a connection error within DJS. That could add another layer of misdirection.

I don't have any solid ideas on how to trap this :/

jschneier commented 1 year ago

This was fixed in #1087