已关闭
[Bug]: `rebuild_dict` loses nested lists under dicts #1001
Nguyễn Thanh Toàn创建于 6月8日关闭于 6月25日
openJiuwen-bot
6月8日 评论:
6月8日 评论:
6月8日 将 iamcandiceguo 设为负责人
6月8日 添加了label:sig/sig-agent-core
openJiuwen-bot
6月8日 评论:
6月8日 评论:
欢迎来到 openJiuwen 社区
Hey @thanhtoantnt , 感谢你对社区的贡献.
机器人使用手册
有关指令的使用,可以点击 此处 查看详情。开发人员可以在每个PR或Issue下方评论特定指令来触发机器人任务。
联系指引
有疑问可以联系 SIG: sig-agent-core ,
维护者是: @seanzhang_cn, @xinyu-jiuwen ,
审核者是: @SnapeK, @alan_cheng, @deyang, @iamcandiceguo .


6月8日 关联了pull request:fix: rebuild_dict loses nested lists under dicts
Checklist
🐞 Detailed Description of the Problem
Severity: HIGH
File:
openjiuwen/core/common/utils/dict_utils.py~line 163Discovered by: Property-based testing (Hypothesis)
Summary
rebuild_dictsilently drops nested lists when a path contains two consecutive list indices. The result is a structurally wrong output with no error raised.Reproducer
from openjiuwen.core.common.utils.dict_utils import extract_leaf_nodes, rebuild_dict data = {'a': [[1]]} leaves = extract_leaf_nodes(data) # leaves: [(['a', '[0]', '[0]'], 1)] result = rebuild_dict(leaves) print(result) # {'a': [{}]} ← wrong, should be {'a': [[1]]}Expected vs Actual
{'a': [[1]]}{'a': [[1]]}{'a': [{}]}Root Cause
The primary bug is in the intermediate traversal loop (~line 163–172). When a path element is a list index (
'[0]') andcurrentis not already a list, the code saves the old reference incurrent_parent_refand rebindscurrentto a new list — but never writes the new list back into the parent.current_parent_refis a dead variable; it is assigned and never read again:# traversal loop — intermediate step (~line 163–176) if not isinstance(current, list): current_parent_ref = current # ← assigned but never used again current = [] # ← local rebind only; parent still holds {} # Expand list to required length while len(current) <= index: current.append({}) current = current[index] # ← steps into {} inside an orphaned listBecause the new list is never linked into the tree, subsequent traversal proceeds through
{}placeholders unreachable fromresult. The same flaw is repeated in the final-value assignment block (~line 189–195):last_key = path[-1] if isinstance(last_key, str) and last_key.startswith('[') and last_key.endswith(']'): index = int(last_key[1:-1]) if not isinstance(current, list): current = [] # ← same dead rebind while len(current) <= index: current.append(None) current[index] = value # ← written to orphaned list, discardedFixing only the final block would leave the traversal bug intact. Both sites need the same fix.
Impact
Affects any structure with a list-of-lists or list-of-dicts-containing-lists pattern:
{'results': [[1, 2], [3, 4]]} {'items': [{'tags': ['a', 'b']}]}The round-trip
extract_leaf_nodes→rebuild_dictis not reliable for these shapes.In current example usage,
stream_inputs_schemavalues are all flat dicts with string refs, so the bug is not triggered by any existing workflow. However, list-valued schemas are a supported shape (the framework handles them invertex.py:453–456), and any user who passes a nested-list schema tostream_inputs_schemawill receive silently corrupted inputs at stream time with no error raised.Suggested Fix
Track
parentandparent_key/parent_indexthrough the loop. At both the intermediate and final list-index sites, write the new list back into the parent before using it:if not isinstance(current, list): new_list = [] if isinstance(parent, list): parent[parent_index] = new_list else: parent[parent_key] = new_list current = new_listThe existing
current_parent_refvariable is a dead stub of exactly this intent — it was clearly meant to enable this write-back but was never wired up.Detailed Environment Information Description
As above.
Additional Information
Version Information
Thanks for your contribution 🎉!