From e436265d6c5d163ae0ca86d3e96e8ed6bb9649b6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 17 Mar 2026 19:21:15 -1000 Subject: [PATCH] [http_request] Prevent double update task launch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guard against launching a second FreeRTOS update task while one is already running. Without this, calling update() twice (e.g. from both the polling interval and the initial check interval) could spawn two concurrent tasks both writing to the same UpdateInfo. With the single-defer structure from the race fix PR, clearing the handle only needs to happen in one place — at the top of the deferred lambda, before any other work. --- .../components/http_request/update/http_request_update.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp index a15dc616753..1c52a281059 100644 --- a/esphome/components/http_request/update/http_request_update.cpp +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -74,6 +74,10 @@ void HttpRequestUpdate::update() { } this->cancel_interval(INITIAL_CHECK_INTERVAL_ID); #ifdef USE_ESP32 + if (this->update_task_handle_ != nullptr) { + ESP_LOGW(TAG, "Update check already in progress"); + return; + } xTaskCreate(HttpRequestUpdate::update_task, "update_task", 8192, (void *) this, 1, &this->update_task_handle_); #else this->update_task(this); @@ -204,6 +208,9 @@ defer: // both success and error paths to avoid multiple std::function instantiations. // Lambda captures only 2 pointers (8 bytes) — fits in std::function SBO on supported toolchains. this_update->defer([this_update, result]() { +#ifdef USE_ESP32 + this_update->update_task_handle_ = nullptr; +#endif if (result->error_str != nullptr) { this_update->status_set_error(result->error_str); delete result;