From b52276056c6c629ffee47ffec695a17a973d4c4e Mon Sep 17 00:00:00 2001 From: Peter Woolery Date: Tue, 12 May 2026 11:40:55 -0700 Subject: [PATCH] fix: cast qty/unit to str before html.escape in vote email shopping preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recipe ingredient qty fields in JSONB are stored as floats (e.g. 1.5), not strings. html.escape() requires str input — AttributeError otherwise. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- backend/app/services/orchestrator/steps.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/app/services/orchestrator/steps.py b/backend/app/services/orchestrator/steps.py index 1c411af..b64bc37 100644 --- a/backend/app/services/orchestrator/steps.py +++ b/backend/app/services/orchestrator/steps.py @@ -170,9 +170,9 @@ def step_email(run: "WeeklyRun", db: "Session") -> None: if all_ingredients: shop_rows = "".join( f"{html.escape(name)}" - f"{html.escape(qty)} {html.escape(unit)}" - f"{html.escape(grocery)}" - f"{html.escape(price)}" + f"{html.escape(str(qty))} {html.escape(str(unit))}" + f"{html.escape(str(grocery))}" + f"{html.escape(str(price))}" for name, (qty, unit, grocery, price) in all_ingredients.items() ) shopping_preview = (