WiFi won't connect¶
This page is for when a board in your workspace won't join wifi, or joins and then behaves strangely. Most week-one wifi trouble is one of five traps: credentials that never reached the board, a silent drop that raises nothing, a connect that freezes everything else, a specific board that needs its transmit power turned down, or a settings.toml that fights the wifi library for the radio.
The functional tests all skip, or a deployed example never joins anything¶
The credentials never reached the board. Wifi credentials start in secrets.toml at the workspace root, which the deploy merges into /runtime_config.msgpack for the board to read back. Workspace setup materializes that file from a template with deliberately bogus placeholder values, so a fresh clone can't join a network by accident, and two states leave you with nothing happening and no wifi error to read:
secrets.tomlis missing. Nothing is staged, soload_runtime_config()on the board raisesOSError. The networking libraries' functional tests catch this at collection time and skip every device test with a message naming the keys they wanted. A deployed example has no such guard: it dies on the board, which you see only if you are tailing the serial output.secrets.tomlis there but still carries the placeholder SSID (replace-with-your-ap-ssid). The functional-test conftests read that placeholder as "no credentials yet" and stage nothing, so those tests skip the same way. A deployed example fails fast instead: its helpers recognize both the in-fileWIFI_SSIDplaceholder and thesecrets.tomlone, and raise immediately with a message naming where to put real credentials.
Fix. Put your real network name and password in the workspace-root secrets.toml, then deploy again:
chumicro-workspace dump-config <project> prints the merged config a deploy would send, so you can confirm wifi.ssid before touching the board, and chumicro-workspace deploy <project> --tail shows what the board says once it boots. (details: Device testing)
The board sits in RECONNECTING, nothing is raised, and wifi.last_error is None¶
On MicroPython on a Pi Pico W (the CYW43 radio), connect() returns right away and leaves isconnected() False without raising anything. There is no exception and no error to read, so code that waits on last_error waits forever.
Fix. Don't gate recovery on last_error. Check wifi.state and wifi.connected instead, which each adapter re-derives from isconnected() after every connect attempt.
Everything else freezes for up to 15 seconds while a CircuitPython board connects¶
CircuitPython's wifi.radio.connect() blocks, and the firmware exposes no non-blocking variant. While the board is CONNECTING or RECONNECTING, every other runner service (an LED heartbeat, an in-flight HTTP request, MQTT keep-alives) pauses, for up to connect_timeout_ms (default 15000).
Fix. Expect the stall on CircuitPython, and connect before you start time-critical work. If a non-blocking connect is load-bearing, run MicroPython on an RP2040, RP2350, or ESP32 board, where wlan.connect() is non-blocking.
Every join attempt fails with status 202 or 205 on a board that worked hours ago¶
A pre-2024 ESP32-S3 (the UM "P4" revision) has vendor-documented wifi instability, worst at full 20 dBm transmit power with native USB. The tell is a marginal signal reading (RSSI around -82 where a healthy board reads -54) and hard join failures on every attempt through radio cycles.
Fix. Turn the radio's transmit power down to about 75% in your deploy config:
CircuitPython maps this to wifi.radio.tx_power and MicroPython to sta.config(txpower=). At txpower=15 the same board joins in about 2 seconds with no loss. This is a config knob only; the library never inspects the board for you.
Flaky or competing wifi on CircuitPython¶
CIRCUITPY_WIFI_SSID and the other CIRCUITPY_WIFI_* keys in settings.toml switch on CircuitPython's own auto-connect supervisor, which then fights chumicro-wifi for control of the radio. settings.toml is CircuitPython-only (MicroPython never reads it) and is reserved for CIRCUITPY_* keys.
Fix. Keep CIRCUITPY_WIFI_* out of settings.toml. Put wifi and app config in secrets.toml, which the deploy converts to runtime_config.msgpack on the board, and ship a settings.toml with no wifi keys. (background: Decision 0057)