Which as far as I can tell is the "task group 1 watchdog".
Does this get reset by the esp_task_wdt_reset(); in the hidden main loop, or is this a different watchdog?
I print debug messages from the main loop every 100 milliseconds so I know for certain that the main loop is not getting blocked for more than a few milliseconds at a time.
(The heap has plenty of free space as do the stacks of the main loop and tasks my code creates.)
This usually happens if you don't use the Arduino stuff but make you own while (1) inside loop() or the like. If loop() doesn't terminate often enough, you may have to call yield() sometimes during it's run.
After more research I think this may be triggered by the RTOS core deciding that task switching is taking too long, possibly due to interrupts being disabled for too long in the MQTT or network code.