esp_http_client appears to cause a memory leak in RTOS task

User avatar
sthivaios
Posts: 5
Joined: Wed Aug 19, 2026 4:35 pm

esp_http_client appears to cause a memory leak in RTOS task

Postby sthivaios » Wed Aug 19, 2026 6:13 pm

Hello all, it's my first time posting here. Hope you are doing well.

I'm writing some firmware for a project, which has to make an HTTP GET request to a server, to get a JSON response. Of course, to do that, I'm using the esp_http_client.

This function (void fetch_schedule_from_alim), is called from inside an RTOS task which runs on an interval. Every 10 seconds (for testing, this will later be 10 minutes but thats irrelevant), that RTOS task reruns, and at some point inside that loop it calls the fetch_schedule_from_alim function. After a lot of logging and debugging, I'm almost 100% certain that the memory leak is not being caused by the task itself, but this function specifically.

The memory leak isn't huge, its around 400 bytes usually, but it varies, sometimes its close to just 100, other times its almost a kilobyte, which suggests that this clearly isn't something simple like a malloc() call not being free'd, since that would be the same amount every time and wouldn't fluctuate.

This is the tetch_schedule_trom_alim function:

Code: Select all

esp_err_t fetch_schedule_from_alim(const char *auth_header, char *out_buf,
                                   size_t out_buf_size) {
  // check if the arguments are invalid
  if (out_buf == NULL || out_buf_size == 0)
    return ESP_ERR_INVALID_ARG;

  // always return a valid empty string, so the caller never parses an
  // uninitialized buffer
  out_buf[0] = '\0';

  // the esp_http_client configuration
  const esp_http_client_config_t config = {
      .url = "[the URL here. ive removed it to post it on the forum]",
      .method = HTTP_METHOD_GET,
      .timeout_ms = 10000,
      .crt_bundle_attach = esp_crt_bundle_attach};

  // init the client and the handle
  const esp_http_client_handle_t client = esp_http_client_init(&config);
  if (!client)
    return ESP_FAIL;

  // set the auth header
  esp_http_client_set_header(client, "Authorization", auth_header);

  // open the client
  const esp_err_t err = esp_http_client_open(client, 0);

  // check if it errored
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "http client open failed: %s", esp_err_to_name(err));
    esp_http_client_cleanup(client);
    return err;
  }

  // read response headers and status code
  esp_http_client_fetch_headers(client);
  const unsigned int status = esp_http_client_get_status_code(client);

  // read the response body into the buffer
  int total = 0;
  while (total < (int)out_buf_size - 1) {
    int r =
        esp_http_client_read(client, out_buf + total, out_buf_size - 1 - total);
    if (r <= 0)
      break;
    total += r;
  }
  out_buf[total] = '\0';

  // close the client and clean everything up
  esp_http_client_close(client);
  esp_http_client_clear_response_buffer(client);
  esp_http_client_cleanup(client);

  // log whether it worked and return OK or FAIL
  ESP_LOGI(TAG, "status=%d, got %d bytes", status, total);
  return (status == 200) ? ESP_OK : ESP_FAIL;
}

As you can see at the end, I'm calling all the cleanup functions for the http_client, so I'm not quite certain what exactly is not being free'd up.

At the top of the RTOS task, I've got a log line which reports the free heap size. Here is that log:

Code: Select all

W (155344) RTOS_FETCH_TASK: Hello from the fetch_task. FREE HEAP: 345972)
[more logs...]
W (195914) RTOS_FETCH_TASK: Hello from the fetch_task. FREE HEAP: 345568)
[more logs...]
W (235374) RTOS_FETCH_TASK: Hello from the fetch_task. FREE HEAP: 345140)
[more logs...]
W (275074) RTOS_FETCH_TASK: Hello from the fetch_task. FREE HEAP: 344944)

The free heap went from 345972 to 345568 to 345140 to 344944 in just 4 re-runs of the task.

I'm at a loss and I would greatly appreciate any help. Thanks in advance, and sorry if this might be a simpler question than I think, I'm fairly new to this.

Sprite
Espressif staff
Espressif staff
Posts: 10658
Joined: Thu Nov 26, 2015 4:08 am

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby Sprite » Thu Aug 20, 2026 1:19 am

I don't see any issues with the code. What you might see is TCP stack housekeeping, i.e. sockets that are held onto after closing them in case more packets appear (or the other side hasn't properly closed them yet). Do you also see the drop happen if you run the loop, say, 50 instead of 4 times?

User avatar
sthivaios
Posts: 5
Joined: Wed Aug 19, 2026 4:35 pm

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby sthivaios » Thu Aug 20, 2026 1:34 am

I don't see any issues with the code. What you might see is TCP stack housekeeping, i.e. sockets that are held onto after closing them in case more packets appear (or the other side hasn't properly closed them yet). Do you also see the drop happen if you run the loop, say, 50 instead of 4 times?

I've left it running for over 2 hours as of right now, and the task takes around 30 seconds and then waits 10 seconds before repeating. So it should've run a solid 150 times by now.

It started at 346556 bytes of free heap and is now at 304132, so thats 42424 bytes gone, a whole 42kB. So, no it seems like a pretty bad leak and I genuinely have no idea where it is coming from.

MicroController
Posts: 2715
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby MicroController » Thu Aug 20, 2026 6:33 am

"Heap tracing" can help you locate where memory is allocated but not freed.

eriksl
Posts: 260
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby eriksl » Thu Aug 20, 2026 7:14 am

And it's not heap fragmentation? In that case the amount of memory "lost" should increase slower over time.

User avatar
sthivaios
Posts: 5
Joined: Wed Aug 19, 2026 4:35 pm

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby sthivaios » Thu Aug 20, 2026 5:21 pm

And it's not heap fragmentation? In that case the amount of memory "lost" should increase slower over time.

I mean the only thing that could've been doing that in this case was me using malloc() in the task but I removed that call and its just a static buffer now, so there shouldn't be anything in this code causing heap fragmentation...

If you guys want more context, this is the actual task:

Code: Select all

// updates the local time on the system by fetching from ntp
static void update_time(void) {
  esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("gr.pool.ntp.org");
  esp_netif_sntp_init(&config);
  if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {
    ESP_LOGE(TAG, "Failed to update system time within 10s timeout");
  } else {
    ESP_LOGI(TAG, "System time updated from gr.pool.ntp.org!");
  }
  esp_netif_sntp_deinit();
}

void fetch_task(void *pvParameters) {

  // setup the watchdog to timeout after 30s
  ESP_LOGI(TAG, "Setting up watchdog");
  const esp_task_wdt_config_t wdt_config = {
      .timeout_ms = 300000,
      .idle_core_mask = 0,
  };
  esp_task_wdt_reconfigure(&wdt_config);

  // buffer for the JSON from the server
  static char json_from_alim_buffer[JSON_BUFFER];

  // ReSharper disable once CppDFAEndlessLoop <-- this is just to get the ide (CLion) to shut up about the endless loop lol
  for (;;) {
    // log the free heap in bytes
    log_free_heap();

    // enable the wdt
    esp_task_wdt_add(nullptr);

    // default delay till the next fetch is 10s
    uint64_t next_delay_ms = SECONDS(2);

    // wake the modem up
    modem_wakeup_or_sleep(true);

    // connect to lte
    ESP_LOGI(TAG, "Calling lte_connect()");
    if (lte_connect() != LTE_CONNECTED_SUCCESSFULLY) {
      ESP_LOGW(TAG, "Skipping this fetch attempt. Retrying in 20 seconds.");
      next_delay_ms = SECONDS(20);
      goto cleanup;
    }

    // update the local time over ntp
    ESP_LOGI(TAG, "Calling update_time()");
    update_time();

    // actually fetch the schedule from ALIM
    ESP_LOGI(TAG, "Calling fetch_schedule_from_alim()");
    fetch_schedule_from_alim(ALIM_AUTHORIZATION_HEADER_DEV,
                             json_from_alim_buffer, JSON_BUFFER);

    // print the response just for debugging
    ESP_LOGI(TAG, "Pulled JSON from ALIM. The raw response follows:");
    printf("%s\n", json_from_alim_buffer);

    // scheduler_unload_nvs_into_ram(); <- commented out for now cuz im debugging the leak

  cleanup:
    // put modem back to sleep again
    esp_modem_set_mode(get_dce(), ESP_MODEM_MODE_COMMAND);
    modem_wakeup_or_sleep(false);

    // disable the wdt again so it doesn't get mad due to the vTaskDelay call
    esp_task_wdt_delete(nullptr);

    // rerun the task again later
    ESP_LOGI(TAG, "Task standing by for %llu seconds",
             (unsigned long long)(next_delay_ms / 1000));
    vTaskDelay(pdMS_TO_TICKS(next_delay_ms));
  }
}

However, to me the task looks perfectly fine and I don't see anything in here that could be leaking memory.

And this is how the task is started/created in app_main():

Code: Select all

// create fetch task
  BaseType_t const fetch_task_returned =
      xTaskCreate(fetch_task, "fetch_task", 12288, NULL, 0,
                  &fetch_task_handle);

  // explode completely if task couldnt be created
  if (fetch_task_returned != pdPASS) {
    ESP_LOGE(TAG, "Failed to create fetch task");
    abort();
  }

"Heap tracing" can help you locate where memory is allocated but not freed.

I'm aware heap tracing is a thing. I tried it and all the calls appear to be parts of ESP-IDF so I can't really understand it. Nothing stood out to me though from the trace dump. I had it start the dump at the beginning of the loop and end/dump before vTaskDelay, with the depth set to 8 (if I recall correctly, because it might have been 6, I'm not sure) in menuconfig. Again, I'm fairly new to this so the heap trace might very well be useful but to me nothing seemed weird there.

MicroController
Posts: 2715
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby MicroController » Fri Aug 21, 2026 7:12 am

You may want to use a larger buffer for the trace records than 8. Then, if the heap trace does not show a "leak" in the monitored code section, your memory leak is most likely in some other piece of code.

eriksl
Posts: 260
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby eriksl » Fri Aug 21, 2026 9:35 am

Yeah indeed. I suspect the bug is in the esp_http_client code (as well).

User avatar
sthivaios
Posts: 5
Joined: Wed Aug 19, 2026 4:35 pm

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby sthivaios » Fri Aug 21, 2026 12:58 pm

Yeah indeed. I suspect the bug is in the esp_http_client code (as well).

At this point, I have 100% confirmed that what is causing this leak is this function, since in the task's code, when I comment out the line with the call to fetch_schedule_from_alim() the leak stops completely and the heap is stable. So it is, in fact, this function.

However, I've gone through it 10 times already. The only thing my function is calling is esp_http_client stuff which obviously is part of ESP-IDF. I am by no means an experienced developer and I hate blaming the issue on something else, because the problem is usually my code, but at this point I'm starting to think it is IDF. It has to be, there's nothing else being called in this function.

I've left it running for 10 hours now, overnight, and it has gone from around 350KB of free heap, to just 68KB. I'm logging it into a CSV file and I wanna see if it'll crash at some point from memory exhaustion (which it probably will). This is not a subtle leak, it lost over 280KB in just 10 hours. In fact I'm almost certain it is leaking even faster now cause in the time it took me to write this post, it went from 68KB to now 66.5KB.

Again I wanna make this clear, I hate blaming other people's code but I don't see how it could be anything but IDF.

I did find some issues regarding memory leaks with the esp_http_client on the ESP-IDF GitHub repo, but from my understanding after skimming through them, they were basically all closed as "intended behavior" unless I didn't read them thoroughly enough. I don't know about you but 280KB of memory loss in 10 hours doesn't sound like intended behavior haha.

For context if anyone is wondering, I'm on ESP-IDF v6.0.1.

eriksl
Posts: 260
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: esp_http_client appears to cause a memory leak in RTOS task

Postby eriksl » Fri Aug 21, 2026 1:03 pm

At this point I think the best approach is to make a bug report on github. There your problem will be seen by much more people from Espressif and they can have a look at the IDF code. I think it's recommendable that you assume the bug is in your code, but really, IDF is big and really, there are bugs in it. I've filed quite a few and most of them have been fixed :)

Who is online

Users browsing this forum: Qwantbot and 0 guests