maximum recursion depth exceeded

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Capstan
Posts: 117
Joined: Sun Jan 29, 2017 4:03 pm
Location: Texas, USA

maximum recursion depth exceeded

Post by Capstan » Tue Feb 28, 2017 12:51 am

I'm seeing this fatal exception occur if I am not really careful about keeping the number of chained function calls down to an absolute minimum, (and I am not using any recursion). Lately I am seeing it when it looks like I should have adequate memory remaining?

stack: 6864 out of 8192
GC: total: 36288, used: 22896, free: 13392
No. of 1-blocks: 349, 2-blocks: 44, max blk sz: 264, max free sz: 644

Is there some way to know the limit and monitor when you are getting close to it? I'm using gc.collect() liberally but doesn't help.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: maximum recursion depth exceeded

Post by deshipu » Tue Feb 28, 2017 8:53 am

If I remember correctly, the recursion limit on MicroPython is 10 -- that's how many nested function calls you can have. For comparison, in cpython, which runs on hardware with orders of magnitude more memory, the limit is 100.

SpotlightKid
Posts: 463
Joined: Wed Apr 08, 2015 5:19 am

Re: maximum recursion depth exceeded

Post by SpotlightKid » Tue Feb 28, 2017 11:40 am

On CPython it's actually 1000.

Code: Select all

import sys; print(sys.getrecursionlimit())
Unfortunately this function seems not to be implemented in MicroPython.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: maximum recursion depth exceeded

Post by pythoncoder » Tue Feb 28, 2017 11:45 am

The following script suggests that the limit for CPython and the Unix build of MicroPython is 990 and 166 respectively. On the Pyboard it was 63 and on the ESP8266 19.

Code: Select all

a = 0
fail = False
def foo():
    global a, fail
    a += 1
    if not fail:
        try:
            foo()
        except:
            fail = True

foo()
print(a)
I'm surprised that even the limit of 19 is being reached in non-recursive code. Are you sure that there is no recursion or interrupt re-entrancy going on?
Peter Hinch
Index to my micropython libraries.

Capstan
Posts: 117
Joined: Sun Jan 29, 2017 4:03 pm
Location: Texas, USA

Re: maximum recursion depth exceeded

Post by Capstan » Tue Feb 28, 2017 2:44 pm

19 seems pretty reasonable. It would be nice to have some function that says how deep you are currently.

I'm trying to gracefully recover from a OSError exception resulting from loss of connection with a server, or from dropped Wifi. The application works fine under normal circumstances, but after a reconnect I am seeing this "recursion depth" happening in code that previously worked.

Maybe I am not handling the exception quite right and have leftovers on the call stack.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: maximum recursion depth exceeded

Post by pythoncoder » Tue Feb 28, 2017 4:39 pm

19 is a lot for normal code. So it's possible that you've hit a bug in the firmware. I'd try to produce a simple test case which demonstrates this, with a view to raising an issue on GitHub if it turns out to be a bug.

My efforts with the ESP8266 (some 6 months ago) suggested it didn't take kindly to WiFi dropouts; alas I never managed to reduce it to a simple test case. I hope - if that turns out to be the problem - you succeed.
Peter Hinch
Index to my micropython libraries.

User avatar
RWLTOK
Posts: 53
Joined: Thu Dec 14, 2017 7:24 pm

Re: maximum recursion depth exceeded

Post by RWLTOK » Sat Apr 04, 2020 1:38 pm

I saw this recently on my pyboard v1.1 with v1.12 (threading) with no where near 19 levels. In my setup, I was running a thread in the background running a command shell. In the foreground, main thread, uasyncio was running some blinking LEDs. The command shell made a call that resulted in somewhere like 13 levels of calling. 13 seemed too small. So I went in and increased the stack size from the default 16k to 32k. Same issue. Huh. I just refactored the code so I had one level less of depth and all is well. I don't know enough how threads are implemented to know if there was something else I could do with the stack size of the thread.

Rich

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: maximum recursion depth exceeded

Post by pythoncoder » Sat Apr 04, 2020 5:40 pm

I never use threading - maybe the limit is less. You could run my above script on the threaded build to check this value.
Peter Hinch
Index to my micropython libraries.

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: maximum recursion depth exceeded

Post by jimmo » Sun Apr 05, 2020 3:04 am

RWLTOK wrote:
Sat Apr 04, 2020 1:38 pm
So I went in and increased the stack size from the default 16k to 32k.
If I understand correctly, you're saying the thread is the one that hit the recursion limit. Changing the limit from 16 to 32 (which I assume you're doing in the linker script) will only affect the main threads.

Threads created with the _thread module on STM32 will have 4kiB stack by default (but this is an option you can configure with _thread.stack_size() ).

Note that there is no hard-coded "recursion depth limit" in terms of number of function calls deep (in MicroPython, I don't know about CPython). It just monitors the stack size compared to the stack limit.

bitrat
Posts: 41
Joined: Fri Jul 26, 2019 4:13 am

Re: maximum recursion depth exceeded

Post by bitrat » Tue May 12, 2020 7:04 am

I know this has been asked elsewhere, but the answer I require hasn't appeared.

My code, which uses threads but has no (intentional) recursive calls is throwing "maximum recursion depth exceeded" exceptions.

Using this test :

Code: Select all

def recursion_check(count):
    try:
        return recursion_check(count+1)
    except:
        return count
I can see that, without threads, the recursion depth is 49 (or more likely 50).

When run inside a thread, the above code returns a paltry 10, regardless of the number of threads or the stack size, which I've tried resetting with

Code: Select all

 _thread.stack_size(16 * 1024)
(my board is an ESP32 with additional 64Mbit PSRAM).

I think this exception is being thrown because a call stack limit is being hit, and has nothing to do with recursion. My code paths are predictable , with few differences between ones that succeed and ones that don't.

On this basis, I'd like to increase the call stack limit, which (given the seemingly constant value of 10) would seem to be hard coded somewhere in the MP source. I've searched in the usual places, but come up empty handed.

Could someone please point the way to this mod?

...without too many suggestions along the lines of converting function calls to loops or not using threads, thanks. :-)

Post Reply