Cache writes are not atomic (embeddings + structured outputs) → an interrupted/concurrent write poisons future reads
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 55/100
Research direction
Start with the embedding read/write paths in src/autointent/_wrappers/embedder/sentence_transformers.py and the structured-output paths in src/autointent/_dump_tools/unit_dumpers.py and src/autointent/generation/_cache.py. Reproduce the truncated .npy and missing model_dump.json cases, then verify that writes are atomic and corrupt or incomplete entries are removed and recomputed instead of raising.
Written by the indexing model from the issue text.
Description
Summary
Both file-based caches write entries in place with no temp-file + atomic rename, and the read paths don't defend against partial/truncated entries. If a writer is interrupted (crash, OOM, kill) or a reader in another process observes a file mid-write, the entry is left partial and every subsequent read of that key raises instead of recomputing — the bad entry poisons the cache until it is deleted by hand. This matters for parallel Optuna workers and the HTTP/MCP server, which can hit the same cache concurrently.
Where (on dev)
Embeddings — src/autointent/_wrappers/embedder/sentence_transformers.py:
- write:
np.save(embeddings_path, ...)straight to the final path (lines ~228–231) - read:
if embeddings_path.exists(): np.load(embeddings_path)with notry/except(lines ~183–185)
Structured outputs — src/autointent/_dump_tools/unit_dumpers.py, PydanticModelDumper.dump (lines 158–165) does mkdir then writes class_info.json and model_dump.json as two separate, non-atomic steps. The read path StructuredOutputCache._load_from_disk (src/autointent/generation/_cache.py) only catches ValidationError / ImportError, so a missing model_dump.json raises an uncaught FileNotFoundError.
Reproduce (no network)
Embeddings — a truncated .npy makes the next embed() raise ValueError (not a miss), permanently:
# after one successful embed(utts), truncate the cached .npy to half its bytes:
raw = embeddings_path.read_bytes()
embeddings_path.write_bytes(raw[: len(raw) // 2])
embedder.embed(utts) # -> raises ValueError; never recomputes
Structured — an entry directory missing model_dump.json (interrupted between the two writes) makes get() raise FileNotFoundError:
cache.set(msgs, Out, params, Out(label="x"))
(entry_dir / "model_dump.json").unlink() # simulate a crash between the two file writes
StructuredOutputCache(use_cache=True).get(msgs, Out, params) # -> raises FileNotFoundError
Both were reproduced in a benchmark: each cache raises on the next read and does not auto-recover.
Suggested fix
- Atomic writes: write to a temp path and
os.replace()(atomic on POSIX) for bothnp.saveand the structured dump (write into a temp directory, then rename it into place). - Self-healing reads: wrap
np.load/PydanticModelDumper.loadso a corrupt/partial entry is deleted and treated as a miss (recompute) instead of raising. For the structured cache, also catchOSError/FileNotFoundError, not justValidationError/ImportError.
Related: #326 (directory-aware deletion is needed for the cleanup path).
Severity
Medium-High under concurrency (parallel trials / long-running server).
How it was found
Robustness scenario of a benchmark of AutoIntent 0.3.1's caches.
- Dominant language
- Python
- Stars
- 53
- Forks
- 16
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from deeppavlov/AutoIntent
-
bug good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
deeppavlov/AutoIntent#352 ·
-
Extract `BaseAPIDescriptionScorer` shared by `LLMDescriptionScorer` and `TypeSafeDescriptionScorer`Openenhancement
Difficulty 4/5 3-5 days Newbie friendliness 48/100
deeppavlov/AutoIntent#357 ·
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 52/100
deeppavlov/AutoIntent#356 ·
-
enhancement
Difficulty 3/5 1-2 days Newbie friendliness 72/100
deeppavlov/AutoIntent#355 ·
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 58/100
deeppavlov/AutoIntent#354 ·
All issues in deeppavlov/AutoIntent
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
BasedHardware/omi#20271 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
openai/openai-cookbook#3153 ·
Maintainers usually reply within 1 day
-
cvss-severity:high devguard l3montree-cybersecurity/devguard/devguard pkg:golang/github.com/l3montree-dev/devguard risk:low state:open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
l3montree-dev/devguard#3146 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
bug confirmed issue
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
open-webui/open-webui#31849 · 2 comments ·
Maintainers usually reply within 1 day