MicroPython MemoryError: memory allocation failed on ESP32, ESP8266 or Pico

Call gc.collect() and build less in RAM. Big strings, lists and imports use up the heap.

What the message means

MicroPython has a small heap. Fragmentation or one large allocation makes the next request fail even when some memory is free.

Fix it in this order

  1. Import gc and call gc.collect() before big operations.
  2. Print gc.mem_free() to see how much is left.
  3. Read files and network data in small chunks.
  4. Use bytearray and preallocated buffers instead of growing strings.
  5. Import only the modules you need, and import them early.
  6. Use a board with more RAM if the program is large.

Why it happens

MicroPython allocates from one heap, and it needs a single contiguous block for each request. After many small allocations and releases the free memory is split into gaps, so a request for a large buffer can fail even though gc.mem_free() reports plenty in total. Building a string with += is a common cause, because each step allocates a new, larger string and leaves the old one as garbage.

Running gc.collect() before a large allocation frees garbage and can merge gaps. Reading a response in chunks into one preallocated bytearray avoids the growth altogether. The micropython.mem_info() call prints a map of the heap, which shows fragmentation directly.

import gc
gc.collect()
print(gc.mem_free())
buf = bytearray(1024)   # allocate once, reuse

The example above has not been run on hardware here; test it on your own board.

If you see this, do this

You seeDo this
Fails when parsing a big responseRead in chunks.
Fails after running a whileFragmentation. Collect and reuse buffers.

main.py at boot, Thonny connection.

Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.

Why this happens

MicroPython takes memory from a single heap, and every object, string, list and function lives there. An allocation needs one contiguous block. After many allocations and releases the free memory splits into pieces, so a request for a large buffer fails even if gc.mem_free() shows more than enough in total. The garbage collector runs when memory is short and also when you call gc.collect(), and it can merge some of the gaps.

Some patterns are costly. Building a string with s += chunk makes a new, larger string every time and leaves the old one as garbage. Parsing a large JSON response creates the whole structure in memory. Importing big modules needs RAM for compiling the source unless the module is a precompiled .mpy file or frozen into the firmware. Boards differ widely, from tens of kilobytes free on an ESP8266 to a few hundred on a Pico, so a script that fits on one may fail on another.

How to confirm the cause

  • Print gc.mem_free() and gc.mem_alloc() at the start, before the failing line and after gc.collect(). If free memory rises a lot after the collect, garbage was the cause.
  • Run micropython.mem_info(1). It prints a map of the heap, and a map full of small used blocks scattered through it shows fragmentation.
  • Read the traceback to find the exact line that failed, and check the size of what it tries to build.
  • Check the size of the data: a response of 30 kB parsed to Python objects takes several times that in RAM.
  • Import modules at the top of the program, before the heap is fragmented, and compare the free memory before and after each import.

Worked example

Reading a file in fixed chunks into one buffer that is allocated once.

import gc
gc.collect()
print(gc.mem_free(), gc.mem_alloc())
buf = bytearray(512)
total = 0
with open('data.txt', 'rb') as f:
    while True:
        n = f.readinto(buf)
        if not n:
            break
        total += n          # handle memoryview(buf)[:n] here
print(total)

Common mistakes

  • Concatenating strings in a loop.
  • Reading a whole file or HTTP response with read() into one object.
  • Storing many numbers in a list when the array module would use less memory.
  • Never calling gc.collect() in a long-running loop.
  • Importing a large module late in the program, after the heap has fragmented.

If this did not fix it

  • Check the stack. A very deep recursion raises a different error, but also shows memory limits.
  • Check network and TLS use. A secure connection needs a large contiguous block, so connect before building big data.
  • Check whether the module can be precompiled with mpy-cross or frozen into the firmware.