You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
errno and strerror attributes incorrectly set on socket errors wrapped by urllib #50720
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=Nonecreated_at=<Date2009-07-12.20:54:33.896>labels= ['type-bug', 'library', '3.9', '3.10', '3.11']
title='errno and strerror attributes incorrectly set on socket errors wrapped by urllib'updated_at=<Date2021-11-30.20:20:38.331>user='https://github.com/ezio-melotti'
In Python 2.6, socket.error was changed to be a child class of IOError 1. IOError derives from EnvironmentError 2, and EnvironmentError
accepts a 2-tuple used to set the values of the errno and strerror
attributes respectively 3.
Apparently the IOError raised by the socket module are instantiated
passing (always?) 'socket error' as first arg and an instance of
socket.gaierror, socket.timeout or socket.herror (and maybe others) as
second arg.
The errno attributes ends up being a string (and not a number) and the
strerror another exception (and not a str):
The 'socket error' strings doesn't provide any useful information
(herror, gaierror and timeout are already subclasses of socket.error)
and it results in confusing messages like:
IOError: [Errno socket error] [Errno 11001] getaddrinfo failed
The relevant information is not accessible directly on the error but it
is in err.strerror/err.args1.
IMHO the first arg should be the errno (if it's available) and the
second the message (e.g. 'getaddrinfo failed' or 'timed out').
The doc of socket.error 1 should be also changed because it says:
"The accompanying value is either a string telling what went wrong or a
pair (errno, string) representing an error returned by a system call,
similar to the value accompanying os.error." (and this is actually what
I'd like it to be, but right now it's something different.)
No, it seems that 2.5 has the same problem. The 'socket error' message is
raised in urllib.py. The socket module is innocent to me...
It appears that this file routinely raises IOErrors, passing various
arguments, which are not stored properly in the IOError object. IMO it
should raise subclasses of IOError.
In this particular case of "socket error", it should let the exception
propagate. Other occurrences need more thinking.
Yes, it looks to me like urllib is intentionally putting the 'socket
error' or 'url error' into the errno position in the IOError arguments.
Now that socket.error is an IOError, that at least seems wrong.
changed the title [-]errno and strerror attributes incorrectly set on socket.error[/-][+]errno and strerror attributes incorrectly set on socket errors wrapped by urllib[/+]on Jul 13, 2009
Can this be fixed without breaking compatibility?
It also affects Python2.7 and maybe also Python 3.x (there the error is different and might be intentional).
Copy/pastable snippet to reproduce the error on 2.x:
from urllib import urlopen
try:
urlopen('http://www.pythonfoobarbaz.org')
except Exception, err:
print 'err:', err
print 'repr(err):', repr(err)
print 'err.errno:', err.errno
print 'err.strerror:', err.strerror
print 'err.strerror.errno:', err.strerror.errno
print 'err.strerror.strerror:', err.strerror.strerror
Result on 2.7:
err: [Errno socket error] [Errno -2] Name or service not known
repr(err): IOError('socket error', gaierror(-2, 'Name or service not known'))
err.errno: socket error
err.strerror: [Errno -2] Name or service not known
err.strerror.errno: -2
err.strerror.strerror: Name or service not known
Copy/pastable snippet to reproduce the error on 3.x:
from urllib.request import urlopen
try:
urlopen('http://www.pythonfoobarbaz.org')
except Exception as exc:
err = exc
print('err:', err)
print('repr(err):', repr(err))
print('err.errno:', err.errno)
print('err.strerror:', err.strerror)
print('err.reason:', err.reason)
print('err.reason.errno:', err.reason.errno)
print('err.reason.strerror:', err.reason.strerror)
Result on 3.2:
err: <urlopen error [Errno -2] Name or service not known>
repr(err): URLError(gaierror(-2, 'Name or service not known'),)
err.errno: None
err.strerror: None
err.reason: [Errno -2] Name or service not known
err.reason.errno: -2
err.reason.strerror: Name or service not known
catherine commented on Jul 29, 2012
catherinemannequin
Mannequin
More actions
It's very hard to tell what ought to be done here, since Lib/urllib/request.py throws URLErrors with a great variety of order and number of arguments, and it's not clear how URLError (in Lib/urllib/error.py) intends to handle them.
However, in this case, AbstractHTTPHandler.do_open is instantiating URLError with another exception instance, and that exception contains .errno and .strerror. URLError puts the entire error instance into reason, where the information is hidden away as .reason.strno and .reason.strerror.
In the name of keeping this information available rather than hiding it, I'm attaching a patch that adds to URLError.__init__:
This is an interesting idea and should at least improve matters. I'm wondering, though...I seem to remember writing code that fished the wrapped error out using one of those attributrs...but I'm not at a computer where I can try to check on that. Hopefully I can check on it this weekend.
err: <urlopen error [Errno -2] Name or service not known>
repr(err): URLError(gaierror(-2, 'Name or service not known'),)
err.reason: [Errno -2] Name or service not known
repr(err.reason): gaierror(-2, 'Name or service not known')
Activity
ezio-melotti commentedon Jul 12, 2009
In Python 2.6, socket.error was changed to be a child class of IOError
1. IOError derives from EnvironmentError 2, and EnvironmentError
accepts a 2-tuple used to set the values of the errno and strerror
attributes respectively 3.
Apparently the IOError raised by the socket module are instantiated
passing (always?) 'socket error' as first arg and an instance of
socket.gaierror, socket.timeout or socket.herror (and maybe others) as
second arg.
The errno attributes ends up being a string (and not a number) and the
strerror another exception (and not a str):
The 'socket error' strings doesn't provide any useful information
(herror, gaierror and timeout are already subclasses of socket.error)
and it results in confusing messages like:
IOError: [Errno socket error] [Errno 11001] getaddrinfo failed
The relevant information is not accessible directly on the error but it
is in err.strerror/err.args1.
IMHO the first arg should be the errno (if it's available) and the
second the message (e.g. 'getaddrinfo failed' or 'timed out').
The doc of socket.error 1 should be also changed because it says:
"The accompanying value is either a string telling what went wrong or a
pair (errno, string) representing an error returned by a system call,
similar to the value accompanying os.error." (and this is actually what
I'd like it to be, but right now it's something different.)
amauryfa commentedon Jul 12, 2009
No, it seems that 2.5 has the same problem. The 'socket error' message is
raised in urllib.py. The socket module is innocent to me...
It appears that this file routinely raises IOErrors, passing various
arguments, which are not stored properly in the IOError object. IMO it
should raise subclasses of IOError.
In this particular case of "socket error", it should let the exception
propagate. Other occurrences need more thinking.
bitdancer commentedon Jul 13, 2009
Yes, it looks to me like urllib is intentionally putting the 'socket
error' or 'url error' into the errno position in the IOError arguments.
Now that socket.error is an IOError, that at least seems wrong.
[-]errno and strerror attributes incorrectly set on socket.error[/-][+]errno and strerror attributes incorrectly set on socket errors wrapped by urllib[/+]ezio-melotti commentedon Feb 27, 2010
Can this be fixed without breaking compatibility?
It also affects Python2.7 and maybe also Python 3.x (there the error is different and might be intentional).
Copy/pastable snippet to reproduce the error on 2.x:
from urllib import urlopen
try:
urlopen('http://www.pythonfoobarbaz.org')
except Exception, err:
print 'err:', err
print 'repr(err):', repr(err)
print 'err.errno:', err.errno
print 'err.strerror:', err.strerror
print 'err.strerror.errno:', err.strerror.errno
print 'err.strerror.strerror:', err.strerror.strerror
Result on 2.7:
err: [Errno socket error] [Errno -2] Name or service not known
repr(err): IOError('socket error', gaierror(-2, 'Name or service not known'))
err.errno: socket error
err.strerror: [Errno -2] Name or service not known
err.strerror.errno: -2
err.strerror.strerror: Name or service not known
Copy/pastable snippet to reproduce the error on 3.x:
from urllib.request import urlopen
try:
urlopen('http://www.pythonfoobarbaz.org')
except Exception as exc:
err = exc
print('err:', err)
print('repr(err):', repr(err))
print('err.errno:', err.errno)
print('err.strerror:', err.strerror)
print('err.reason:', err.reason)
print('err.reason.errno:', err.reason.errno)
print('err.reason.strerror:', err.reason.strerror)
Result on 3.2:
err: <urlopen error [Errno -2] Name or service not known>
repr(err): URLError(gaierror(-2, 'Name or service not known'),)
err.errno: None
err.strerror: None
err.reason: [Errno -2] Name or service not known
err.reason.errno: -2
err.reason.strerror: Name or service not known
catherine commentedon Jul 29, 2012
It's very hard to tell what ought to be done here, since Lib/urllib/request.py throws URLErrors with a great variety of order and number of arguments, and it's not clear how URLError (in Lib/urllib/error.py) intends to handle them.
However, in this case, AbstractHTTPHandler.do_open is instantiating URLError with another exception instance, and that exception contains .errno and .strerror. URLError puts the entire error instance into
reason, where the information is hidden away as .reason.strno and .reason.strerror.In the name of keeping this information available rather than hiding it, I'm attaching a patch that adds to URLError.__init__:
Again, I'm not sure this is the most logical approach because I can't find a consistent pattern in the ways URLError is instantiated.
bitdancer commentedon Aug 3, 2012
This is an interesting idea and should at least improve matters. I'm wondering, though...I seem to remember writing code that fished the wrapped error out using one of those attributrs...but I'm not at a computer where I can try to check on that. Hopefully I can check on it this weekend.
ezio-melotti commentedon Sep 19, 2012
That would be err.reason:
prints:
err: <urlopen error [Errno -2] Name or service not known>
repr(err): URLError(gaierror(-2, 'Name or service not known'),)
err.reason: [Errno -2] Name or service not known
repr(err.reason): gaierror(-2, 'Name or service not known')
bitdancer commentedon Sep 19, 2012
Ah, of course. I should have reread the whole issue :)
The backward compatibility is the big concern here. Regardless of what we do about that, we should at least fix this in 3.4.
iritkatriel commentedon Nov 30, 2021
Reproduced on 3.11: