Summary
Disabling the AutoAP fallback while no WiFi SSID is configured leaves the device
with no network interface at all. WEB_Utils::setup() still starts the web
server, and lwip aborts. The device then reboots in a loop and can only be
recovered over USB.
On a remote or hard-to-reach installation (a hilltop digipeater, for example)
this means physically retrieving the device.
Reproduction
- Leave the WiFi SSID empty (normal for a digipeater with no network on site).
- Uncheck AutoAP in the web configuration — a natural thing to do to save power
on a solar-powered site.
- Reboot.
Serial output
SPIFFS Mounted
Reading config..
Config read successfuly
[NM] Initializing Networking...
Starting Station: <CALL> Version: 2026-04-21
(DigiEcoMode: OFF)
init : LoRa Module ... done!
WiFi SSID not set!
assert failed: tcpip_api_call IDF/components/lwip/lwip/src/api/tcpip.c:497 (Invalid mbox)
Backtrace: 0x40083e2d:0x3ffcd1c0 0x40094df5:0x3ffcd1e0 0x4009a765:0x3ffcd200 ...
Rebooting...
…and the same sequence repeats indefinitely.
Cause
In WIFI_Utils::startWiFi(), with no SSID and AutoAP disabled, neither STA nor AP
is started:
if (!networkManager->hasWiFiNetworks()) {
Serial.println("WiFi SSID not set!");
if (Config.wifiAutoAP.enabled) {
Serial.println("Starting AP fallback...");
startAutoAP();
}
return;
}
setup() then continues with the network-dependent modules. Three of them guard
on connectivity, one does not:
| module |
guard |
NTP_Utils::setup() |
networkManager->isConnected() && ecoMode == 0 |
SYSLOG_Utils::setup() |
networkManager->isConnected() |
WX_Utils::setup() |
wxsensor.active (not network) |
WEB_Utils::setup() |
ecoMode == 0 only |
So WEB_Utils::setup() registers its handlers, calls OTA_Utils::setup(&server)
and then server.begin() with no netif initialised — hence the lwip assert.
This also explains why ecoMode = 2 (WiFi off) does not crash: the same
ecoMode == 0 condition skips the web server. Only the autoAP = false +
ecoMode = 0 combination reaches server.begin() without a network.
Suggested fix
Align the guard with the other three modules:
void setup() {
if (Config.digi.ecoMode == 0 && networkManager->isConnected()) {
...
server.begin();
}
}
A second safeguard worth considering: refuse to disable AutoAP from the web form
when no SSID is set, since that combination leaves no way back in.
Tested on a TTGO LoRa32 v2.1.6, V3.2.4.
Summary
Disabling the AutoAP fallback while no WiFi SSID is configured leaves the device
with no network interface at all.
WEB_Utils::setup()still starts the webserver, and lwip aborts. The device then reboots in a loop and can only be
recovered over USB.
On a remote or hard-to-reach installation (a hilltop digipeater, for example)
this means physically retrieving the device.
Reproduction
on a solar-powered site.
Serial output
…and the same sequence repeats indefinitely.
Cause
In
WIFI_Utils::startWiFi(), with no SSID and AutoAP disabled, neither STA nor APis started:
setup()then continues with the network-dependent modules. Three of them guardon connectivity, one does not:
NTP_Utils::setup()networkManager->isConnected() && ecoMode == 0SYSLOG_Utils::setup()networkManager->isConnected()WX_Utils::setup()wxsensor.active(not network)WEB_Utils::setup()ecoMode == 0onlySo
WEB_Utils::setup()registers its handlers, callsOTA_Utils::setup(&server)and then
server.begin()with no netif initialised — hence the lwip assert.This also explains why
ecoMode = 2(WiFi off) does not crash: the sameecoMode == 0condition skips the web server. Only theautoAP = false+ecoMode = 0combination reachesserver.begin()without a network.Suggested fix
Align the guard with the other three modules:
A second safeguard worth considering: refuse to disable AutoAP from the web form
when no SSID is set, since that combination leaves no way back in.
Tested on a TTGO LoRa32 v2.1.6, V3.2.4.