Skip to content

urequests.get in Micropython randomly results in OSError 103 and 104 as well as ValueError #785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
nanowiz opened this issue Jan 5, 2024 · 7 comments

Comments

@nanowiz
Copy link

nanowiz commented Jan 5, 2024

I am using urequest.get in Micropython running on a Raspberry Pi PICO W in a loop containing the following to access Ecobee's server for my furnace status:

url = "https://api.ecobee.com/1/thermostatSummary?format=json&body={\"selection\":{\"selectionType\":\"registered\",\"selectionMatch\":\"\",\"includeEquipmentStatus\":true}}"
headers = {
        'Content-Type': 'text/json',
        'Authorization': f'Bearer {accessToken}'
}
response = urequests.get(url, headers=headers)
rstatus = response.status_code
data = response.json()
response.close()

This works most of the time, but the code will randomly crash with either OSError 104 or OSError 103 or ValueError. The following are REPL outputs of these errors.

Traceback (most recent call last):
File "", line 157, in
File "", line 52, in furnaceStatus
File "requests/init.py", line 180, in get
File "requests/init.py", line 125, in request
OSError: -104

Traceback (most recent call last):
File "", line 166, in
File "", line 52, in furnaceStatus
File "requests/init.py", line 180, in get
File "requests/init.py", line 130, in request
ValueError: HTTP error: BadStatusLine:
[]

I understand that the OSError 104 and 103 are network response issues. It would be much better if they can be handled with a returned status code rather than causing an OSError. According to the githib code at line 130 of request in requests/init.py, it is complaining about an invalid response presumabily from the internet response. Again, it would be more desirable to be handled with a status code response rather than causing a program crash.

@ned-pcs
Copy link

ned-pcs commented Jan 18, 2024

OSError 104 is ECONNRESET. Which can be caused by one end or the other closing a socket too soon.
But one should usually enclose network functions in try/except blocks anyway:

url = "https://api.ecobee.com/1/thermostatSummary?format=json&body={\"selection\":{\"selectionType\":\"registered\",\"selectionMatch\":\"\",\"includeEquipmentStatus\":true}}"
headers = {
        'Content-Type': 'text/json',
        'Authorization': f'Bearer {accessToken}'
}
try:
    response = urequests.get(url, headers=headers)
    rstatus = response.status_code
    data = response.json()
    response.close()
except OSError, ValueError:
    data = None
    rstatus = 500

@nanowiz
Copy link
Author

nanowiz commented Jan 20, 2024 via email

@joshunagy
Copy link

joshunagy commented Jan 14, 2025

Hi Sammy,

I'm also seeing a very similar problem and I can't figure it out. I'm new to MicroPython so I'm still leaning the ropes, so please forgive me.
I'm also using urequest but a post(), not a get() and see very similar occasional OSError 103 errors. I also see the same "stickiness", where it sometimes starts to always respond like this and doesn't stop. When the OSError occurs there's a long delay after the request.post(). I have the post happening in an asyncio function. When the post works, it's super fast, but when it doesn't, it take anywhere from 5-20 seconds to respond with the error. I've only seen the OSError 104 once in my days of testing, but that could have just been a momentary wifi/internet connection issue. My internet and Wifi are pretty solid. Using Postman the API always responds instantly. I'm posting to a very simple self hosted PHP script right now. I can see the apache logs and there's nothing obviously wrong with the requests (that I can see).

I'm pretty sure it was working reliably at one point, though I could have been wrong. I'm going to strip my program back to just the absolute essentials and see if I can get the posts to be reliable again.

Have you discovered anything since your last post?

@nanowiz
Copy link
Author

nanowiz commented Jan 14, 2025 via email

@joshunagy
Copy link

joshunagy commented Jan 14, 2025

No problem, I get it. But thanks for the quick response!
I "feel" like it's resource issue, almost like my urequest.close() isn't isn't actually closing the sockets and they're building up, or some resource leak like that, or the async function is trying to grab a resource at the same time as another async function. Anyways, I'll keep stripping down my app until I find it and I'll post it if I figure it out.

@joshunagy
Copy link

joshunagy commented Jan 14, 2025

So I've stripped by script down to the basics and I'm still having the issue.

`import urequests
import network
import time

ssid="MySSID"
password="MyKey"

url = "http://mydomain.com/api.php"
data = {"mac_addr": "aabbccddee"}
headers = {"Content-Type": "application/json"}

fail_count = 0
success_count = 0

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

print("Starting")

while True:

while wlan.isconnected() == False:
    print("Connecting to Wifi...")
    wlan.connect(ssid, password)
    
    
    time.sleep(3)
    if wlan.isconnected() == True:
        print("WiFi Manager: Connected")


if wlan.isconnected() == True:

    try:
        print("Sending POST Request")
        response = urequests.post(url, json=data, headers=headers)
        print(response.text)
        response.close()
        success_count += 1
    
    except OSError as error:
        print ("Error with REST API call. " + str(error.errno) + " Error: " + str(error) )
        fail_count += 1
        
print("Update attempts. Success: " + str(success_count) + " Failed: " + str(fail_count))       
time.sleep(10)

`

The URL in the snippet is obviously not what I'm actually using but you can see from the REPL what it returns.

'Sending POST Request
{"mac_addr":"aabbccddee","temp_scale":"C","temp_low_value":"19","timestamp":"Tue, 14 Jan 2025 11:42:12 +0000"}
Update attempts. Success: 38 Failed: 0
Sending POST Request
{"mac_addr":"aabbccddee","temp_scale":"C","temp_low_value":"19","timestamp":"Tue, 14 Jan 2025 11:42:23 +0000"}
Update attempts. Success: 39 Failed: 0
Sending POST Request
{"mac_addr":"aabbccddee","temp_scale":"C","temp_low_value":"19","timestamp":"Tue, 14 Jan 2025 11:42:33 +0000"}
Update attempts. Success: 40 Failed: 0
Sending POST Request

<title>408 Request Timeout</title>

Request Timeout

Server timeout waiting for the HTTP request from the client.

Update attempts. Success: 41 Failed: 0
Sending POST Request
Error with REST API call. 103 Error: [Errno 103] ECONNABORTED
Update attempts. Success: 41 Failed: 1
Sending POST Request
Error with REST API call. 103 Error: [Errno 103] ECONNABORTED
Update attempts. Success: 41 Failed: 2
Sending POST Request
{"mac_addr":"aabbccddee","temp_scale":"C","temp_low_value":"19","timestamp":"Tue, 14 Jan 2025 11:44:16 +0000"}
Update attempts. Success: 42 Failed: 2
Sending POST Request
Error with REST API call. 103 Error: [Errno 103] ECONNABORTED
Update attempts. Success: 42 Failed: 3
Sending POST Request
Error with REST API call. 103 Error: [Errno 103] ECONNABORTED
Update attempts. Success: 42 Failed: 4
Sending POST Request
{"mac_addr":"aabbccddee","temp_scale":"C","temp_low_value":"19","timestamp":"Tue, 14 Jan 2025 11:45:24 +0000"}
Update attempts. Success: 43 Failed: 4
'

At one point the API response timed out, which I've never seen before, so maybe that's a hint as to what's happening. But as you can see once the 103 errors start, they keep going. It's almost as if the sockets aren't getting closed and once it runs out, that's it. I'm wondering if there's something in my API response that's causing the issue. I'm going to try changing the POST to a GET and see what happens, and will also try changing the response from the API and see what I get. Two separates tests...

@joshunagy
Copy link

Just to follow up... I figured it out, for the most part. After striping down the app to the absolute bare minimum, trying GET's instead of POSTs, modifying the API responses to an absolute minimum, I continued to have the Error: [Errno 103] ECONNABORTED errors in the order of around 20% of the time. Even worse, it would occasionally get sticky and always return an Error: [Errno 103] ECONNABORTED error with the urequest.post() and urequest.get(). Not only that, but it would sometimes take 10-40 seconds to even respond with the error and would hang everything in the meantime. I would need to reboot the PICO to clear it.

I deduced down that the wifi.isconnected() would return True, but I really don't think it was actually fully / properly connected. Also, sometimes the wlan.connect(ssid, key) would take many, many tries to connect. At this point, I suspected the physical Wifi layer being the problem. I know the PICO W only supports 2.4Ghz. I have a Unifi network setup with both 2.4Ghz and 5Ghz on the same SSID. It's been a VERY solid WiFi setup. I rarely have any Wifi issues except, I know some of my other devices in my house that only use 2.4GHz don't like the dual band SSIDs. So I decided to switch the PICO to a 2.4Ghz SSID only as a test. In the process of adding this new SSID with 2.4Ghz only, it must have "restarted" the WiFi across all configured SSIDs because I lost WIfi for a moment on my laptop. After that, everything started to work!! No more multiple attempts to connect to WiFi. No more Error: [Errno 103] ECONNABORTED. The problem was just gone. I assumed it couldn't be a problem with the access points because everything else in my house using Wifi worked great.

Now I've been building this app on the PICO W on and off for weeks now. When I first started, I had no issues. Over time this issues got worse and worse, which is why I just couldn't figure out what I changed with the app to cause the issue. It wasn't the app. I suspect the constant connect/reconnect of the PICO to the access point(s) caused an issue on the access points and the restart cleared the issue. I put my original version of the app back on the PICO, with the first dual band SSID and it worked great! 1000 urequests.post() and 0 errors. What an ordeal.

However, that said, it would be really handy to get more details on networking related errors when they occur. I spent hours trying to figure out what the [Errno 103] ECONNABORTED meant, and because I can't see open sockets, or file handles or any network details on the PICO I found it super hard to diagnose. Most posts I found related to [Errno 103] ECONNABORTED where due to not issuing urequests.close() which we result in running out of available sockets, which makes sense. When/if the issue happens again I set up a constant ping to the PICO IP and see how it responds, or use wireshark to monitor the traffic.

I hope this bit of information helps anybody else in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants