From 69e27fe3e7848a5a149a3a5562ff60aafd86805c Mon Sep 17 00:00:00 2001 From: Nick Huo Date: Wed, 9 Sep 2026 14:55:44 -0700 Subject: [PATCH 1/2] Fix malformed-JSON handling and undefined error_message in deploy path - deploy.py: POST / silently coerced a malformed JSON body to {} via get_json(force=True, silent=True), dispatching the request anyway and surfacing a misleading "missing positional argument" error from the workflow function instead of the real parse problem. Now rejects a non-empty, invalid/non-object body with 400 and the actual JSON decode error; an empty body still defaults to {} for all-default-arg workflows. - local_controller_frontend.py: WriteResult referenced an undefined error_message when relaying a result to on_result(), throwing on every successful write and logging a misleading "WriteResult failed" error after the result had already been persisted. error_message is now read from the same "error" field _send_result_callback sends. Co-Authored-By: Claude Sonnet 5 --- canyonos_core/controller/deploy.py | 19 +++++++++++++++++-- .../controller/local_controller_frontend.py | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/canyonos_core/controller/deploy.py b/canyonos_core/controller/deploy.py index f480dc4..8618570 100644 --- a/canyonos_core/controller/deploy.py +++ b/canyonos_core/controller/deploy.py @@ -180,8 +180,23 @@ def _execute_workflow(request_id, kwargs, context=None): @app.route(f"/{fn_name}", methods=["POST"]) def handle_workflow(): """Accept a workflow request, dispatch async, return request ID.""" - # Parse request body as JSON args for the workflow function - kwargs = request.get_json(force=True, silent=True) or {} + # An empty body is a valid no-args call (workflows may have all-default + # params). A non-empty body that isn't a valid JSON object is rejected + # here with the real parse error, instead of being coerced to {} and + # surfacing later as a misleading "missing argument" error from the + # workflow function itself. Parsed with the stdlib json module + # directly (not request.get_json) because Flask/Werkzeug replaces the + # actual decode error with a generic "Bad Request" message. + raw_body = request.get_data(cache=True) + if raw_body: + try: + kwargs = json.loads(raw_body) + except json.JSONDecodeError as e: + return jsonify({"error": f"Invalid JSON in request body: {e}"}), 400 + if not isinstance(kwargs, dict): + return jsonify({"error": "Request body must be a JSON object"}), 400 + else: + kwargs = {} # Extract policy context (if provided) before passing to workflow context = kwargs.pop("_context", {}) diff --git a/canyonos_core/controller/local_controller_frontend.py b/canyonos_core/controller/local_controller_frontend.py index ec1da4e..f3f2881 100644 --- a/canyonos_core/controller/local_controller_frontend.py +++ b/canyonos_core/controller/local_controller_frontend.py @@ -54,6 +54,7 @@ def WriteResult(self, request, context): future_id = data.get("future_id") result = data.get("result") failed = int(bool(data.get("failed", 0))) + error_message = data.get("error", "") logger.info( f"WriteResult: received result for future {future_id}: {result}" From 575c1b64cf23ed0347332aa476aa54297f8fe624 Mon Sep 17 00:00:00 2001 From: Nick Huo Date: Thu, 10 Sep 2026 10:51:57 -0700 Subject: [PATCH 2/2] fix error msg --- canyonos_core/controller/deploy.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/canyonos_core/controller/deploy.py b/canyonos_core/controller/deploy.py index 8618570..f053927 100644 --- a/canyonos_core/controller/deploy.py +++ b/canyonos_core/controller/deploy.py @@ -191,8 +191,9 @@ def handle_workflow(): if raw_body: try: kwargs = json.loads(raw_body) - except json.JSONDecodeError as e: - return jsonify({"error": f"Invalid JSON in request body: {e}"}), 400 + except json.JSONDecodeError: + logger.warning("Invalid JSON in request body.", exc_info=True) + return jsonify({"error": "Invalid JSON in request body"}), 400 if not isinstance(kwargs, dict): return jsonify({"error": "Request body must be a JSON object"}), 400 else: