[Bug]: JsonCache.get() crashes with unhandled AttributeError on non-dict or invalid envelope JSON payloads
维护者通常 5 天内回复
还没有人认领这个 Issue。
- #1 来自 @wangkangmao —— 已关闭,未合并
评估
调研方向
阅读 packages/graphrag-cache/graphrag_cache/json_cache.py,并将 JsonCache.get() 与 issue 中描述的 SQLiteCache 行为进行比较。检查缓存测试,并为有效但不是字典的 JSON 值,以及缺少 result 的字典补充测试覆盖。完成标准是删除无效条目,且 get() 不抛出异常并返回 None。
由索引模型根据 Issue 内容生成。
描述
Do you need to file an issue?
- I have searched the existing issues and this bug is not already filed.
- I believe this is a legitimate bug, not just a question. If this is a question, please use the Discussions area.
Describe the bug
In packages/graphrag-cache/graphrag_cache/json_cache.py, JsonCache.get() decodes stored cache data using json.loads(data) and assumes the deserialized object is always a dictionary:
async def get(self, key: str) -> Any:
"""Get method definition."""
if await self.has(key):
try:
data = await self._storage.get(key)
data = json.loads(data)
except UnicodeDecodeError:
await self._storage.delete(key)
return None
except json.decoder.JSONDecodeError:
await self._storage.delete(key)
return None
else:
return data.get("result")
If the storage contains a valid JSON payload that is not a dictionary (e.g. a JSON array [1, 2, 3], primitive string, number, or boolean from an external tool, corrupted state, or older schema format), json.loads() succeeds without raising JSONDecodeError. Then execution jumps to data.get("result"), immediately raising:
AttributeError: 'list' object has no attribute 'get'
Furthermore, unlike SQLiteCache (which explicitly handles invalid envelopes and purges corrupted entries via if not isinstance(data, dict) or "result" not in data:), JsonCache neither catches this exception nor deletes the offending key. As a result, every subsequent call to cache.get(key) repeatedly crashes the pipeline instead of recovering gracefully with None.
Steps to reproduce
Self-contained minimal reproduction (no external APIs or configs needed):
import asyncio
import json
class InMemoryStorage:
def __init__(self):
self._store = {}
async def get(self, key):
return self._store.get(key)
async def set(self, key, value):
self._store[key] = value
async def has(self, key):
return key in self._store
async def delete(self, key):
self._store.pop(key, None)
# Directly reproduces packages/graphrag-cache/graphrag_cache/json_cache.py
class JsonCache:
def __init__(self, storage):
self._storage = storage
async def get(self, key: str):
if await self.has(key):
try:
data = await self._storage.get(key)
data = json.loads(data)
except UnicodeDecodeError:
await self._storage.delete(key)
return None
except json.decoder.JSONDecodeError:
await self._storage.delete(key)
return None
else:
return data.get("result")
return None
async def has(self, key: str) -> bool:
return await self._storage.has(key)
async def main():
storage = InMemoryStorage()
cache = JsonCache(storage)
# Store a valid JSON array or primitive payload under a cache key
await storage.set("bad_envelope", "[1, 2, 3]")
# Crashes with unhandled AttributeError: 'list' object has no attribute 'get'
result = await cache.get("bad_envelope")
print("Result:", result)
asyncio.run(main())
Expected Behavior
Consistent with SQLiteCache, JsonCache.get() should verify that isinstance(data, dict) and "result" in data. If invalid, it should purge the corrupted key from storage and safely return None.
Proposed fix:
async def get(self, key: str) -> Any | None:
"""Get method definition."""
if await self.has(key):
try:
data = await self._storage.get(key)
data = json.loads(data)
except (UnicodeDecodeError, json.decoder.JSONDecodeError):
await self._storage.delete(key)
return None
else:
if not isinstance(data, dict) or "result" not in data:
await self._storage.delete(key)
return None
return data["result"]
return None
GraphRAG Config Used
N/A (Reproducible directly in graphrag_cache.json_cache.JsonCache)
Logs and screenshots
Traceback (most recent call last):
File "repro.py", line 47, in <module>
asyncio.run(main())
File ".../asyncio/runners.py", line 190, in run
return runner.run(main)
File ".../asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
File ".../asyncio/base_events.py", line 654, in run_until_complete
return future.result()
File "repro.py", line 43, in main
result = await cache.get("bad_envelope")
File "repro.py", line 32, in get
return data.get("result")
AttributeError: 'list' object has no attribute 'get'
Additional context
- GraphRAG Version:
mainbranch (post-monorepo split / PR #2591) - Python Version: Python 3.10 / 3.11 / 3.12
- Operating System: Linux / macOS / Windows
- Note: We have prepared a fix with regression tests and can submit a PR if this looks good to maintainers.
- 主要语言
- Python
- 星标
- 36.6k
- 派生
- 3.9k
- 平均合并
- 4 天 11 小时
- 30 天内合并 PR
- 1
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
microsoft/graphrag 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 74/100
microsoft/graphrag#2626 · 1 条评论 ·
维护者通常 5 天内回复
-
[Bug]: response_format_json_object=True is silently dropped, so JSON mode never reaches the model未关闭bug triage
难度 2/5 1-3 小时 新手友好度 72/100
microsoft/graphrag#2625 · 1 条评论 ·
维护者通常 5 天内回复
-
难度 1/5 1 小时以内 新手友好度 95/100
维护者通常 5 天内回复
-
难度 2/5 1-3 小时 新手友好度 85/100
microsoft/graphrag#2594 · 1 条评论 ·
维护者通常 5 天内回复
-
[Bug]: TokenChunker never terminates when chunking overlap >= size (no validation of size/overlap)未关闭
难度 2/5 1-3 小时 新手友好度 78/100
microsoft/graphrag#2593 · 2 条评论 ·
维护者通常 5 天内回复
查看 microsoft/graphrag 的全部 Issue
相似的 Issue
-
bug
难度 1/5 1 小时以内 新手友好度 78/100
splunk/security_content#4418 ·
维护者通常 1 天内回复
-
[Bug / Enhancement]: Improve teleop_robot CLI with configurable timeout, robust input validation, and clean ROS shutdown可能已有人在做 @muskan-creates352 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 3 天内回复
-
bug(pipelines): shortcode stripping deletes text between a {{< >}} shortcode and the next {{% %}}可能已有人在做 @Ashborne-lab 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 70/100
kubeflow/docs-agent#293 ·
维护者通常 3 天内回复
-
难度 2/5 1-3 小时 新手友好度 62/100
Imbad0202/academic-research-skills#1093 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
pierreaubert/gpui-toolkit#114 ·
维护者通常 1 天内回复