fix(networking): catch real exceptions in get_external_ip fallback chain#3318
Open
ArtificialXai wants to merge 2 commits intolatent-to:stagingfrom
Open
Conversation
basfroman
requested changes
Apr 20, 2026
Collaborator
basfroman
left a comment
There was a problem hiding this comment.
Hey @ArtificialXai, pls read CONTRIBUTING.md to move forward with your pr.
3dea36d to
7f31808
Compare
Author
|
Thanks for the pointer, @basfroman. Read
Ready for another look when you have a minute. |
Contributor
Your commit still isn't signed |
Closes latent-to#3309. Each provider in `get_external_ip` was wrapped in `except ExternalIPNotFound`, but none of the underlying calls (`requests.get`, `ip_to_int`, `os.popen`+`readline`, `urllib.request.urlopen`, `json.loads`, wikipedia header lookup) ever raise `ExternalIPNotFound`. As a result the first failing provider crashed the entire function instead of falling through to the next one. Catch the exceptions that can actually occur: * RequestException — for `requests.get` failures * AddrFormatError — for malformed IPs * OSError — for `os.popen`/curl failures * URLError — for urllib failures * ValueError — for json + int parse failures * KeyError — for the wikipedia header * AssertionError — for the isinstance guards * ExternalIPNotFound — kept for backward compat Three regression tests cover: AWS connection error → curl fallthrough, malformed AWS IP → curl fallthrough, and all-providers-exhausted → ExternalIPNotFound.
7f31808 to
d361f28
Compare
Author
|
Signed and re-pushed ( |
thewhaleking
approved these changes
Apr 24, 2026
Author
|
Hey @basfroman, friendly ping — addressed all your feedback in the 2026-04-20 comment (rebased onto staging, commit message follows 6-rule style, tests cover the exceptions). Commit is now signed as of today (2026-04-24). Could you take another look when you get a moment? Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #3309.
Each provider in
get_external_ipis wrapped inexcept ExternalIPNotFound, but none of the underlying calls (requests.get,ip_to_int,os.popen+readline,urllib.request.urlopen,json.loads, the Wikipedia header lookup) ever raiseExternalIPNotFound. As a result the first failing provider crashes the entire function instead of falling through to the next one — exactly the symptom reported in the issue (arequests.exceptions.ConnectionErrorpropagates out when AWS is unreachable, rather than the curl fallback being attempted).Fix
Replace each
except ExternalIPNotFound:with a tuple of exceptions that the providers actually raise:requests.exceptions.RequestExceptionrequests.get(...)(AWS, Wikipedia)netaddr.core.AddrFormatErrorip_to_int(...)with malformed inputOSErroros.popen(...)+readline()(ifconfig.me, ipinfo.io, dnsomatic)urllib.error.URLErrorurllib_request.urlopen(...)(ident.me)ValueErrorjson.loads(...)parse failures,int(...)parse failuresKeyErrorX-Client-IPheaderAssertionErrorassert isinstance(ip_to_int(...), int)guardExternalIPNotFoundThe set is defined once at module scope as
_IP_LOOKUP_EXCEPTIONSso the providers stay in sync.Tests
Three new regression tests in
tests/unit_tests/utils/test_networking.py:test_get_external_ip_aws_connection_error_falls_through_to_curl— AWSrequests.getraisesConnectionError, curl fallback returns a valid IP, function returns that IP (was: raisedConnectionError).test_get_external_ip_malformed_ip_falls_through— AWS returns a non-IP string (triggersAddrFormatErrorinip_to_int), curl fallback succeeds.test_get_external_ip_all_providers_exhausted_raises— every provider raises its real exception; function must raiseExternalIPNotFound(not leak the last underlying exception).All 22 tests in
tests/unit_tests/utils/test_networking.pypass locally.Test plan
pytest tests/unit_tests/utils/test_networking.py— all 22 passNotes
assert isinstance(ip_to_int(external_ip), int)line is tautological (ip_to_inteither returnsintor raises), but left unchanged to keep this PR narrow and focused on the reported bug.