Skip to content

network_provisioning: update_wifi_scan_results() reports empty scan collection as success and drops SCAN_DONE on !scanning (IEC-566) #787

Description

@grasmash

Answers checklist

  • I have read the component documentation and the issue is not addressed there.
  • I am using target and esp-idf version as defined in the component's idf_component.yml.
  • I have searched the issue tracker for a similar issue and not found any related issue.

Which component are you using?

network_provisioning

ESP-IDF version

v5.3.2

Development Kit

Custom ESP32-S3 board

Used Component version

espressif/network_provisioning 1.0.2 (defect verified still present on master / 1.2.4 — see below)

Bug: update_wifi_scan_results() reports an empty scan collection as success, and silently drops SCAN_DONE events

In src/manager.c, update_wifi_scan_results() has two related issues that make a failed/racy Wi-Fi scan during provisioning indistinguishable from a genuine "no networks in range" result. Downstream, the provisioning app is told the scan succeeded with zero APs, so the user sees an empty network list instead of an error, dead-ending BLE provisioning.

This code is unchanged between 1.0.2 and current master (1.2.4), so both points below reproduce on the latest release. Line numbers below are from 1.0.2.

1. An empty collection is returned as ESP_OK.

static esp_err_t update_wifi_scan_results(void)
{
    ...
    if (esp_wifi_scan_get_ap_num(&count) != ESP_OK) {
        ESP_LOGE(TAG, "Failed to get count of scanned APs");
        goto exit;               // ret == ESP_FAIL
    }

    if (!count) {
        ESP_LOGD(TAG, "Scan result empty");
        ret = ESP_OK;            // <-- empty == success
        goto exit;
    }
    ...
}

count == 0 from esp_wifi_scan_get_ap_num() is treated as a successful "no networks" result. But the same zero count is also produced when the scan never actually collected anything — e.g. a scan started before the radio/scan machinery was ready. Because it returns ESP_OK, the caller and the provisioning protocomm handler cannot tell "genuinely no APs in range" from "the scan failed to collect results." The app-facing result is an empty AP list with a success status, which surfaces to the user as "no networks found."

2. A SCAN_DONE event that arrives when prov_ctx->scanning is false is dropped.

static esp_err_t update_wifi_scan_results(void)
{
    if (!prov_ctx->scanning) {
        return ESP_ERR_INVALID_STATE;   // <-- SCAN_DONE silently discarded
    }
    ...
}

If a WIFI_EVENT_SCAN_DONE is delivered when the manager does not believe it is scanning (a state/timing race around scan start/stop), the collected result is discarded with no retry and no signal to the provisioning flow — another path to a lost/empty scan result.

Field evidence

Found via AI-assisted hardware-in-the-loop testing (co-authored with Claude). We ran a headless BLE-provisioning probe that repeatedly issues the scan_wifi_APs command right after the device enters provisioning mode:

  • 9 scan attempts, 3 returned empty, in an environment with multiple strong APs consistently visible to the same device outside provisioning.
  • Empty and populated scans took an identical ~5.25s. That is the duration of a full sequential 14-channel sweep, so the empty results are every channel collected empty, not a truncated or aborted sweep.

The identical full-sweep duration for empty results points at a readiness/timing race: the scan is requested and runs to completion, but collects nothing on any channel — and that empty collection is then reported to the app as a successful zero-AP result via the ESP_OK path in (1). This intermittency (empty right after entering provisioning mode) is what makes it user-visible as a flaky "no networks found."

Suggested direction

  • Distinguish an empty collection from a genuine zero-AP result — e.g. return a distinct error (or set a flag) on the empty path in (1) rather than ESP_OK, so the provisioning handler can retry or report a scan failure instead of an empty list.
  • Avoid silently dropping a SCAN_DONE that arrives while !prov_ctx->scanning in (2) — at minimum log it; ideally still collect/retry so the result is not lost.

Because (1) changes the return semantics of update_wifi_scan_results() (which other callers/handlers depend on), we did not want to presume the fix shape. Happy to open a PR if you can confirm the preferred direction (distinct error code vs. an out-param/flag).

Transparency

This defect was root-caused with AI assistance (Claude) as part of hardware-in-the-loop testing of our own product firmware. The repro described above is exactly the headless ble_prov scan_wifi_APs probe we ran (9 scans, 3 empty, identical ~5.25s duration); we have not run any repro beyond that.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions