[Bug]: JsonCache.get() crashes with unhandled AttributeError on non-dict or invalid envelope JSON payloads
I maintainer di solito rispondono entro 5 giorni
Nessuno ha ancora preso questa issue.
- #1 di @wangkangmao — chiusa senza merge
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 82/100
Direzione di ricerca
Leggi packages/graphrag-cache/graphrag_cache/json_cache.py e confronta JsonCache.get() con il comportamento di SQLiteCache descritto nell’issue. Controlla i test della cache e aggiungi la copertura per i valori JSON validi che non sono dizionari e per i dizionari a cui manca result. Il lavoro è completato quando le voci non valide vengono eliminate e get() restituisce None senza sollevare eccezioni.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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.
- Lingua principale
- Python
- Stelle
- 36.6k
- Fork
- 3.9k
- Merge medio
- 4g 11h
- PR unite (30g)
- 1
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di microsoft/graphrag
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
microsoft/graphrag#2626 · 1 commento ·
I maintainer di solito rispondono entro 5 giorni
-
[Bug]: response_format_json_object=True is silently dropped, so JSON mode never reaches the modelApertabug triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
microsoft/graphrag#2625 · 1 commento ·
I maintainer di solito rispondono entro 5 giorni
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 95/100
I maintainer di solito rispondono entro 5 giorni
-
[Bug]: JSONLinesFileReader drops rows containing U+2028, U+2029 or U+0085 (uses str.splitlines)Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
microsoft/graphrag#2594 · 1 commento ·
I maintainer di solito rispondono entro 5 giorni
-
[Bug]: TokenChunker never terminates when chunking overlap >= size (no validation of size/overlap)Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
microsoft/graphrag#2593 · 2 commenti ·
I maintainer di solito rispondono entro 5 giorni
Tutte le issue di microsoft/graphrag
Issue simili
-
Input: placeholder drawn in the text colour when the empty Input is focused but not yet editedAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
pierreaubert/gpui-toolkit#114 ·
I maintainer di solito rispondono entro 1 giorno
-
intake mcp-intake needs-human-review priority:high type:bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
Ikalus1988/MisakaNet#4903 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
FinanceFlash/unvibecode#819 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno