ESP32 Thread (Border Router) stop issues / esp_openthread_stop()

ole--hc
Posts: 1
Joined: Thu Aug 13, 2026 11:12 am

ESP32 Thread (Border Router) stop issues / esp_openthread_stop()

Postby ole--hc » Tue Aug 25, 2026 8:57 am

Hey,
I ran into an issue regarding the ESP32 Thread Border router shutdown. I have opened an issue-ticket for this problem on the ESP-IDF Github but don't seem to get a reply, so I wondered if anyone on this forum had a similar experience before or has a working Thread shutdown implemented in their own project.

Here is the Issue description as documented on Github:
### Answers checklist.

- [x] I have read the documentation [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/) and the issue is not addressed there.
- [x] I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
- [x] I have searched the issue tracker for a similar issue and not found a similar issue.

### IDF version.

6.0.2 & 5.5.3

### Espressif SoC revision.

ESP32 (host) + CC2652P7 as RCP

### Operating System used.

Linux

### How did you build your project?

VS Code IDE

### If you are using Windows, please specify command line type.

None

### Development Kit.

Custom Board

### Power Supply used.

USB

### What is the expected behavior?

I want to shut the Thread stack down at runtime, without rebooting. After disabling the stack with otThreadSetEnabled(instance, false) and otIp6SetEnabled(instance, false), I expect esp_openthread_stop() to tear down everything belonging to the Thread stack and its IPv6 interface: the mainloop task, the netif glue etc. and to leave the device in a clean state.

From there I should be able to either re-initialise Thread or bring up a different protocol on the same host.

### What is the actual behavior?

The device panics inside FreeRTOS:

Code: Select all

assert failed: xQueueGenericSend queue.c:936 (pxQueue)

The backtrace shows that the ESP tries to push something to a already deleted Queue and the Microcontroller crashes. Backtrace placed into DEBUG LOGS section.

### Steps to reproduce.

1. Bring up an OpenThread Border Router with esp_openthread_init() + esp_openthread_border_router_init(), netif glue attached as usual, Ethernet as backbone.
2. Let the device run for a few seconds.
3. From a task other than the OpenThread mainloop task, run the following shutdown sequence (error handling trimmed for readability):

Code: Select all

esp_err_t ThreadController::stop()
{
    esp_openthread_register_rcp_failure_handler(nullptr);

    esp_openthread_lock_acquire(portMAX_DELAY);
    esp_openthread_border_router_deinit();
    esp_openthread_lock_release();

    otInstance *instance = esp_openthread_get_instance();

    if (!esp_openthread_lock_acquire(portMAX_DELAY)) {
        ESP_LOGE(TAG, "Could not acquire OpenThread lock");
        return ESP_ERR_TIMEOUT;
    }

    otError ot_error = OT_ERROR_NONE;

    if (otThreadGetDeviceRole(instance) != OT_DEVICE_ROLE_DISABLED) {
        ot_error = otThreadSetEnabled(instance, false);
    }

    if (ot_error == OT_ERROR_NONE && otIp6IsEnabled(instance)) {
        ot_error = otIp6SetEnabled(instance, false);
    }

    while (otTaskletsArePending(instance)) {
        otTaskletsProcess(instance);
    }

    esp_openthread_lock_release();

    // barrier / delay to let pending esp_event and lwIP work drain

    return esp_openthread_stop();   // <-- assert happens here
}
### Debug Logs.

Code: Select all

E (71375) OPENTHREAD: esp_openthread_platform_process(217): process dns_upstream_qu failed
E (71385) OPENTHREAD: esp_openthread_platform_process failed
D (71385) event: running post OPENTHREAD_EVENT:10 with handler 0x401133cc and context 0x3ffdbdf0 on loop 0x3ffc9654
--- 0x401133cc: esp_netif_action_leave_ip6_multicast_group at <IDF_PATH>/components/esp_netif/esp_netif_handlers.c:108
D (71405) esp_netif_handlers: esp_netif action leave_ip6_multicast_group with netif0x3ffdb8d8 from event_id=10

assert failed: xQueueGenericSend queue.c:936 (pxQueue)

Backtrace: 0x4008a7c9:0x3ffcb590 0x4008a795:0x3ffcb5b0 0x40089c1a:0x3ffcb5d0 0x401eefac:0x3ffcb6f0 0x4011fc1f:0x3ffcb730 0x40114a5b:0x3ffcb760 0x4011f75a:0x3ffcb790 0x4010a54d:0x3ffcb7b0 0x4010a5b0:0x3ffcb800 0x4010ac12:0x3ffcb830 0x4010af57:0x3ffcb870 0x40113b29:0x3ffcb8b0 0x40113ab5:0x3ffcb900 0x400ffb50:0x3ffcb920
--- 0x4008a7c9: panic_abort at <IDF_PATH>/components/esp_system/panic.c:464
--- 0x4008a795: esp_system_abort at <IDF_PATH>/components/esp_system/port/esp_system_chip.c:87
--- 0x40089c1a: __assert_func at <IDF_PATH>/components/esp_libc/src/assert.c:81
--- 0x401eefac: xQueueGenericSend at <IDF_PATH>/components/freertos/FreeRTOS-Kernel/queue.c:937
--- 0x4011fc1f: openthread_netif_transmit at <IDF_PATH>/components/openthread/src/esp_openthread_netif_glue.c:210
--- 0x40114a5b: esp_netif_transmit at <IDF_PATH>/components/esp_netif/lwip/esp_netif_lwip.c:1433
--- 0x4011f75a: openthread_output_ip6 at <IDF_PATH>/components/openthread/src/esp_openthread_lwip_netif.c:52
--- 0x4010a54d: ip6_output_if_src at <IDF_PATH>/components/lwip/lwip/src/core/ipv6/ip6.c:1295
--- 0x4010a5b0: ip6_output_if at <IDF_PATH>/components/lwip/lwip/src/core/ipv6/ip6.c:1185
--- 0x4010ac12: mld6_send at <IDF_PATH>/components/lwip/lwip/src/core/ipv6/mld6.c:662
--- 0x4010af57: mld6_leavegroup_netif at <IDF_PATH>/components/lwip/lwip/src/core/ipv6/mld6.c:473
--- 0x40113b29: esp_netif_leave_ip6_multicast_group_api at <IDF_PATH>/components/esp_netif/lwip/esp_netif_lwip.c:2957
--- 0x40113ab5: esp_netif_api_cb at <IDF_PATH>/components/esp_netif/lwip/esp_netif_lwip.c:227
--- 0x400ffb50: tcpip_thread at <IDF_PATH>/components/lwip/lwip/src/api/tcpip.c:136
https://github.com/espressif/esp-idf/issues/18973

Who is online

Users browsing this forum: Semrush [Bot] and 1 guest