Comfy-Org / Comfy-Org/ComfyUI

V3 `PriceBadge` JSONata expressions: `COMBO` widget values are silently lowercased before evaluation

Open
#13,837 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
133k
Forks
15.7k
Avg merge
1d 7h
Merged PRs (30d)
158

Description

## Summary

When the ComfyUI frontend evaluates a node's `price_badge` JSONata expression, `COMBO` (and `STRING`) widget values are silently **lowercased** before being injected into the `widgets` context. This is undocumented on the backend `IO.PriceBadge` API, and bites anyone who writes case-sensitive `` / `` checks against user-facing combo labels.

## Where it happens

[`ComfyUI_frontend/src/composables/node/useNodePricing.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/src/composables/node/useNodePricing.ts) (`normalizeWidgetValue` / context-building, around L201–L246) coerces values by widget type:

- `INT` / `FLOAT` → number
- `BOOLEAN` → boolean
- `COMBO` / `STRING` → `value.trim().toLowerCase()`

## Reproducer

A node with a combo whose options are user-facing labels:

`python
IO.Combo.Input("model", options=["Gemini Flash Lite", "Gemini 2.5 Flash"], default="Gemini Flash Lite")
`

…and a price_badge that branches on the label:

`jsonata
(
:= widgets.model;
(, "Flash Lite") ? { "type": "list_usd", "usd": [0.00025, 0.0015] }
: (, "2.5 Flash") ? { "type": "list_usd", "usd": [0.0003, 0.0025] }
: { "type":"text", "text":"Token-based" }
)
`

…always falls through to the `Token-based` branch, because at evaluation time `widgets.model = "gemini flash lite"` (lowercased), and JSONata `` is case-sensitive. Switching the substrings to `"flash lite"` / `"2.5 flash"` (or wrapping with `()`) fixes it.

The existing partner LTXV node coincidentally avoids the bug because its expression already uses `(widgets.model)` and lowercase keys (`"ltx-2 (pro)"`); the lowercasing then becomes idempotent.

## Why this is a footgun

1. `IO.PriceBadge` is a backend Python API; partner authors writing JSONata expressions don't typically read the frontend source.
2. The behaviour silently turns case-sensitive `` checks into mismatches without producing any error — the badge just shows the fallback text.
3. There's no warning at registration time even though the frontend has full type info on each widget when the expression is parsed.

## Suggested fixes (in order of effort)

**Documentation (smallest):** Add a note on the docstring of `PriceBadge.expr` and `PriceBadgeDepends` in [`comfy_api/latest/_io.py`](https://github.com/Comfy-Org/ComfyUI/blob/main/comfy_api/latest/_io.py) explicitly stating that `COMBO` and `STRING` widget values are lowercased+trimmed in the JSONata context, with a one-line example showing the lowercase-substring idiom.

**Frontend (medium):** Stop normalizing `COMBO` values; trim+lowercase only `STRING`. Combo *values* are usually code-like identifiers that authors compare by exact match. (This would, however, break the LTXV expression's lookup — so it has to be guarded by a backend-versioned schema flag or done in lockstep with a partner-node sweep.)

**Frontend (largest):** Expose a `widgets_raw` (or similar) escape hatch alongside the normalized `widgets`, so authors who need exact-match comparisons can opt out.

I'd vote for the documentation fix shipping immediately and the frontend question being treated as a separate decision.

## Discovery context

Hit while building a third-party Remote Node Protocol (RNP/1) prototype where the same V3 `PriceBadge` shape is round-tripped over HTTP. The normalization is invisible from a partner-author POV until the badge silently falls through.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.