UI→API conversion drops a record-valued widget (ImageCropV2.crop_region) and runs the node with its default

Aperta
#1,011 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@allenflux ci sta già lavorando.

Dal 16/10/2026.

  • #1016 di @allenflux — aperta

Valutazione

Difficoltà
3/5
Tempo stimato
Mezza giornata
Idoneità per principianti
66/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
python
Ambito
cli, tooling

Direzione di ricerca

Start in workflow_to_api.py at _collect_widget_inputs (around L1671), which hands the whole node to _absorb_dict_widget_values (around L1714) whenever any widget value is a dict. Run the repro from the issue against convert_ui_to_api and confirm crop_region comes back as the schema default. Done when the record in widgets_values lands on its socketless widget and the Power Lora path still works.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

comfy-cli 1.22.0 (comfy-mcp 0.10.0 on top of it), ComfyUI 0.38.x, Windows 11. Reproduced on main (workflow_to_api.py, _collect_widget_inputs at L1671 and _absorb_dict_widget_values at L1714).

What happens

A node whose widget stores a record in widgets_values loses that value in the UI→API conversion. ImageCropV2 stores its crop_region (type BOUNDING_BOX, socketless: true) as {"x", "y", "width", "height"}; the converted prompt carries the schema default {"x": 0, "y": 0, "width": 512, "height": 512} instead. The job runs, so nothing warns: in the bundled 3d_pixal3d_multi_views template the four crops all become the same 512×512 corner of the input picture, the four "views" fed to Pixal3DMultiViewConditioning are identical, and the generated mesh is a radially symmetric object instead of the pictured one. The same workflow queued from the frontend gives the right prompt.

Repro (self-contained: the two schemas as GET /object_info returns them on ComfyUI 0.38, the node as the frontend saves it)

from comfy_cli.workflow_to_api import convert_ui_to_api
object_info = {
  "LoadImage": {"input": {"required": {"image": [["house.png"], {"image_upload": True}]}}, "input_order": {"required": ["image"]},
                "output": ["IMAGE", "MASK"], "output_name": ["IMAGE", "MASK"]},
  "ImageCropV2": {"input": {"required": {"image": ["IMAGE", {}],
                   "crop_region": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": True, "component": "ImageCrop"}]}},
                  "input_order": {"required": ["image", "crop_region"]}, "output": ["IMAGE"], "output_name": ["IMAGE"]},
}
wf = {"nodes": [
  {"id": 364, "type": "LoadImage", "widgets_values": ["house.png", "image"], "outputs": [{"name": "IMAGE", "type": "IMAGE", "links": [1]}]},
  {"id": 338, "type": "ImageCropV2",
   "inputs": [{"name": "image", "type": "IMAGE", "link": 1},
              {"name": "crop_region", "type": "BOUNDING_BOX", "widget": {"name": "crop_region"}, "link": None}],
   "widgets_values": [{"x": 0, "y": 0, "width": 1669, "height": 2688}, 0, 0, 512, 512]}],
  "links": [[1, 364, 0, 338, 0, "IMAGE"]], "version": 0.4}
print(convert_ui_to_api(wf, object_info)["338"]["inputs"]["crop_region"])

Observed: {'x': 0, 'y': 0, 'width': 512, 'height': 512}. Expected: {'x': 0, 'y': 0, 'width': 1669, 'height': 2688}. The trailing 0, 0, 512, 512 are the Custom-ratio sub-widgets the frontend also serializes; with them removed the result is the same.

Why

_collect_widget_inputs sends the whole node through _absorb_dict_widget_values as soon as any value in the list is a dict (L1671). That function only understands Power Lora entries (a dict with type or lora); every other record is skipped, the input is never set, and _collect_default_inputs fills it from the schema. _is_widget_input does give crop_region a slot (it is socketless), so this is not the missing-slot case of #893: the slot exists, the value is thrown away by the dict shortcut.

Same shape for any socketless input whose frontend widget serializes a record: CreateBoundingBoxes.last_incoming, CropByBBoxes.bboxes, SAM3_Detect.bboxes, DrawBBoxes.bboxes, VideoTrim.trim, VideoCrop.crop (VIDEO_EDIT), CurveEditor.curve, Painter.mask, ImageCompositor.compositor, ImageCompare.compare_view, ResolutionSelector.preview on this install.

Suggestion

Take the Power Lora shortcut only when the dicts actually look like Power Lora entries (type/lora keys), and run the normal schema walk otherwise, letting a record land on its widget like a scalar does. Pairing by name (#873) would also solve it.

Workaround we use

Rewriting the node's widgets_values as a dict ({"crop_region": {...}}) before conversion: the converter already honours that form and the prompt comes out as saved.

Lingua principale
Python
Stelle
1k
Fork
176
Merge medio
1g 11h
PR unite (30g)
87

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Comfy-Org/comfy-cli

Tutte le issue di Comfy-Org/comfy-cli

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.