UI→API conversion drops a record-valued widget (ImageCropV2.crop_region) and runs the node with its default
メンテナーはふだん 1 日以内に返信
評価
調査の方向性
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.
索引モデルが issue の本文から書いたものです。
説明
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.
- 主要言語
- Python
- スター
- 1k
- フォーク
- 176
- 平均マージ
- 1日 11時間
- マージ済み PR(30日)
- 87
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Comfy-Org/comfy-cli のほかの issue
-
test_file_utils umask tests assert against a umask the code never reads (import-time _UMASK), so they only pass on a 0o022 host対応中かも @neverbiasu が 10 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
Comfy-Org/comfy-cli#907 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 1/5 1時間未満 初心者へのやさしさ 92/100
Comfy-Org/comfy-cli#781 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
`comfy launch --background` fails with FileNotFoundError when comfy-cli is invoked by path対応中かも @RaphaelFakhri が 42 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Comfy-Org/comfy-cli#691 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
Comfy-Org/comfy-cli#670 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
Comfy-Org/comfy-cli の issue をすべて見る
似ている issue
-
add entry to blockオープン
難易度 1/5 1時間未満 初心者へのやさしさ 65/100
StevenBlack/hosts#3299 ·
-
`garak --report` overwrites the input report when its name has no ".report"対応中かも @0z5a が今日担当しました。 オープンneeds-triage
難易度 2/5 半日 初心者へのやさしさ 72/100
メンテナーはふだん 2 日以内に返信
-
plot_graph crashes when a mesh node has no m2m edge対応中かも @tygvi が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
mllam/neural-lam#883 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
future-agi/future-agi#4092 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
transcript analytics: a text whose only protected spans the prose pass redacts is withheld wholeオープン
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
WingedGuardian/GENesis-AGI#4641 ·
メンテナーはふだん 1 日以内に返信