From bd442155ba8c4d9aa052db4658d443222c2a4f19 Mon Sep 17 00:00:00 2001 From: packerlschupfer <83344883+packerlschupfer@users.noreply.github.com> Date: Fri, 31 Jul 2026 01:22:30 +0200 Subject: [PATCH] =?UTF-8?q?Moonraker:=20pass=20print=3Dtrue=20in=20upload?= =?UTF-8?q?=20=E2=80=94=20fixes=20Upload=20&=20Print=20race=20with=20power?= =?UTF-8?q?-on-upload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #14945. Upload & Print on the Moonraker (Klipper) host type failed with HTTP 503 "Klippy Host not connected" on any printer that Moonraker powers up in response to an upload (the [power] on_when_upload_queued feature). The file landed on disk, the print never started, and the user hit an error dialog. Root cause: after POST /server/files/upload succeeds we immediately fire POST /printer/print/start. On a cold printer that Moonraker just powered up, Klippy is still coming up when /printer/print/start arrives, so Moonraker returns 503. Fix: add `print=true` to the upload multipart form. Moonraker's own upload endpoint queues the print inside the upload response — and when a [power] device with on_when_upload_queued is configured, it powers the printer on and waits for Klippy READY before starting. That's the whole point of the power-on-upload feature; our second POST was defeating it. Also read `result.print_started` from the upload response — when true, skip our explicit /printer/print/start (Moonraker handled it); when false (older Moonraker or buddy-fork that ignores the print flag), fall back to the explicit call so the existing behaviour is preserved for those servers. Reporter and root-cause identification: @RubenOllesch. --- src/slic3r/Utils/Moonraker.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/slic3r/Utils/Moonraker.cpp b/src/slic3r/Utils/Moonraker.cpp index f1ca432390..a62e55206a 100644 --- a/src/slic3r/Utils/Moonraker.cpp +++ b/src/slic3r/Utils/Moonraker.cpp @@ -212,13 +212,10 @@ bool Moonraker::start_print(wxString &error_msg, const std::string &filename) co bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn progress_fn, ErrorFn error_fn, InfoFn info_fn) const { - //ORCA: POST /server/files/upload as multipart/form-data with: - // file = - // root = (Moonraker default: "gcodes") - // Successful response shape: - // { "result": { "item": { "path": ".gcode", "root": "" }, "print_started": } } - // We always start the print explicitly via /printer/print/start regardless of `print_started` - // so the user can rely on a single call site for state. + // POST /server/files/upload with `print=true` so Moonraker queues the print + // itself and respects [power] on_when_upload_queued (issue #14945). Older + // Moonrakers that ignore the flag return print_started=false and we fall + // back to the explicit /printer/print/start below. wxString test_msg; if (!test(test_msg)) { error_fn(std::move(test_msg)); @@ -233,9 +230,12 @@ bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn progress_fn, Erro // addition later (storage picker) needs no change to this method. const std::string root = upload_data.storage.empty() ? std::string("gcodes") : upload_data.storage; + const bool want_start = upload_data.post_action == PrintHostPostUploadAction::StartPrint; + std::string url = make_url("server/files/upload"); bool result = true; std::string uploaded_path; + bool moonraker_started_print = false; //ORCA: gcode inside a .gcode.3mf is index-coded (Metadata/plate_.gcode), so the upload names the // plate via a 1-based `plateindex` (set only in the .3mf path, see Plater::send_gcode_legacy); @@ -249,13 +249,14 @@ bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn progress_fn, Erro % root % upload_filename.string() % (plateindex.empty() ? "-" : plateindex) - % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false"); + % (want_start ? "true" : "false"); auto http = Http::post(std::move(url)); set_auth(http); http.form_add("root", root); if (!plateindex.empty()) http.form_add("plateindex", plateindex); + http.form_add("print", want_start ? "true" : "false"); http.form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: upload HTTP %2%: %3%") % name % status % body; @@ -278,6 +279,7 @@ bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn progress_fn, Erro "%1%: upload response missing result.item.path, falling back to original filename `%2%`") % name % uploaded_path; } + moonraker_started_print = ptree.get("result.print_started", false); } catch (const std::exception &ex) { BOOST_LOG_TRIVIAL(warning) << boost::format( "%1%: could not parse upload response (%2%); falling back to original filename") @@ -306,7 +308,8 @@ bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn progress_fn, Erro if (!result) return false; - if (upload_data.post_action == PrintHostPostUploadAction::StartPrint && !uploaded_path.empty()) { + // Fallback when Moonraker ignored the `print` flag or reported print_started=false. + if (want_start && !uploaded_path.empty() && !moonraker_started_print) { wxString start_msg; if (!start_print(start_msg, uploaded_path)) { error_fn(std::move(start_msg));