From bc788d008e7156ab96b06d92038c496c03878405 Mon Sep 17 00:00:00 2001 From: DanS Date: Fri, 12 Jun 2026 11:31:50 -0500 Subject: [PATCH] fix(send): poll z_getoperationstatus without the per-opid filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The opid poll called z_getoperationstatus(["opid"]) to check a specific operation, but this daemon rejects the filtered form with "JSON value is not a number/array as expected" (a UniValue error returned as an RPC error). The poll's catch swallowed it, so every completed send stayed stuck on "Waiting for operation" forever — confirmed via a Windows debug-log capture showing the throw on every 2s cycle. The no-arg form works (verified in the console). Call z_getoperationstatus with no arguments (returns ALL operations) and filter to the opids we're tracking in parseOperationStatusPoll(). The parser now skips any operation whose id isn't in the requested set, so unrelated/old operations can't fire a spurious error toast or pollute send state. The stale-opid logic is unchanged (the no-arg form still reports in-progress ops, so a genuinely pending opid is never misread as stale). Co-Authored-By: Claude Opus 4.8 --- src/app.cpp | 8 +++++--- src/services/network_refresh_service.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 1d9fe8b..b129489 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -774,12 +774,14 @@ void App::update() opidWorker->post([this, opids]() -> rpc::RPCWorker::MainCb { auto* rpc = (fast_rpc_ && fast_rpc_->isConnected()) ? fast_rpc_.get() : rpc_.get(); if (!rpc) return [this](){ opid_poll_in_progress_ = false; }; - json ids = json::array(); - for (const auto& id : opids) ids.push_back(id); json result; try { rpc::RPCClient::TraceScope trace("Send tab / Operation status"); - result = rpc->call("z_getoperationstatus", {ids}); + // No per-opid filter: this daemon rejects z_getoperationstatus(["opid"]) with + // "JSON value is not an array as expected", which left completed sends stuck on + // "Waiting for operation". The no-arg form returns ALL operations; + // parseOperationStatusPoll() filters down to the opids we're tracking. + result = rpc->call("z_getoperationstatus", json::array()); } catch (...) { return [this](){ opid_poll_in_progress_ = false; }; } diff --git a/src/services/network_refresh_service.cpp b/src/services/network_refresh_service.cpp index 284c5cb..e8b462f 100644 --- a/src/services/network_refresh_service.cpp +++ b/src/services/network_refresh_service.cpp @@ -1072,11 +1072,17 @@ NetworkRefreshService::OperationStatusPollResult NetworkRefreshService::parseOpe OperationStatusPollResult parsed; if (!result.is_array()) return parsed; + // We poll z_getoperationstatus with no filter (this daemon rejects the per-opid filtered form), + // so the result lists ALL operations. Only act on the ones we're tracking — otherwise an + // unrelated failed/old operation would fire a spurious error toast or pollute send state. + const std::set requested(requestedOpids.begin(), requestedOpids.end()); + std::set reported; for (const auto& op : result) { if (!op.is_object()) continue; std::string opid = op.value("id", std::string()); if (opid.empty()) continue; + if (requested.find(opid) == requested.end()) continue; // not one of ours — ignore reported.insert(opid); std::string status = op.value("status", std::string());