The Field Guide to AI Memory Field Guide
IV — Building it for real · 11 min

How Memory Systems Break in Production

A field catalog of how AI memory systems fail, each with its symptom, root cause, and the fix that worked, from fan-out amplification and score-fusion bugs to hallucinated IDs, silent outages, and confabulation.

Most memory bugs do not announce themselves. A retrieval system that returns the wrong chunk looks identical to one returning the right chunk: text comes back, the model answers, no stack trace. A background extraction job dead for two weeks looks the same as a system with nothing to remember. The interesting failures are silent, plausible, or both.

What follows is a catalogue drawn from production memory systems (MemoryPlugin and AskLibrary among them) and the open-source field. Each entry has the same shape: the symptom you observe, the cause underneath, and the fix that worked. Some of these we lived and the entry runs long; some we read about and it does not. They fall into three families: infrastructure that fails quietly, retrieval that surfaces the wrong thing, and an LLM corrupting the store it maintains.

#Fan-out amplification: one flaky call, multiplied

This is the one that cost us a month of confused bug reports, so it gets the long version.

A feature passes every test, then fails for real users at a rate nobody can explain. In our knowledge-graph builder, 8 of 16 runs failed over a month, and one user with a large bucket failed six times out of six, never once succeeding. The job fanned out roughly 14 structured-output LLM calls in parallel and waited on all of them. Each failed independently about 5% of the time, returning JSON that would not validate against the schema. With N independent calls at per-call failure rate p, the whole job fails at 1 - (1 - p)^N, which is about 50% at p of 5% and N of 14, almost exactly the 8-of-16 we were seeing. The bigger the bucket, the more batches, the more dice rolls, which is why the heavy user never got a clean run. A job-level retry made it worse on cost and no better on success, because it re-ran all 14 calls and re-rolled every die.

We reached for a model change first, and it backfired instructively. Swapping the fan-out stages to a stronger model (DeepSeek V4 Flash) for cleaner structured output just moved the failure: it ran slower, and under the same 14-way concurrency it timed the whole graph job out at thirty minutes. The thing that actually fixed it was boring. A bounded retry around each individual call (three attempts, exponential backoff, bail immediately on non-transient errors like a bad key or a quota wall) plus partial degradation, so one dead batch costs a few entities instead of the whole graph. Failure probability compounds across fan-out, and you fight it at the call, not the job. The Cost and latency page works through the arithmetic.

#Score fusion across mismatched scales

A hybrid search configured as "70 percent semantic" behaves like a keyword engine. An audit found results fused as a weighted sum, dense times 0.7 plus sparse times 0.3. But dense is a cosine value near 0 to 1, while raw BM25 (the keyword-relevance score) is unbounded, usually 5 to 30. A perfect semantic hit with no keyword overlap (cosine 0.92, BM25 0) fuses to 0.64; a mediocre keyword match (cosine 0.55, BM25 14) fuses to 4.59, beating it by seven times.

The fix: fuse by rank, not raw score. Reciprocal Rank Fusion adds 1/(k + rank) across lists, the scale mismatch cannot happen, and it needs no re-embedding. The rule underneath is the one to keep: never linearly combine scores that live on different scales. Hybrid retrieval covers fusion in depth.

#Garbage memories suppress recall

A safety-trained model refuses to use injected memory at all, sometimes saying out loud that the memories would "just add more clutter." The injected list in one case held entries like "A cat is better than a bat", a bare "...", and four near-identical copies of a casual greeting. Low-value and duplicate memories do not merely waste tokens. They hand the model a concrete reason to reject the whole recall protocol, and a delivery format that reads as prompt injection compounds it (see privacy and pitfalls). The fix is to score quality at save time, refusing greetings, small talk, and short fragments, dedupe server-side before injection, and cap the injected set to a few strong examples rather than a dozen mixed ones.

Lesson: hygiene is a recall feature. Garbage does not just dilute the context, it degrades the model's willingness to use any of it.

#Hallucinated IDs

A curation job that mutates memory starts throwing ownership errors about missing IDs, because the LLM proposed operations on records that do not exist. Models invent identifiers: ask one for the IDs of memories to merge or delete and it will sometimes return a UUID it never saw, or one already deleted mid-run. Two defences stack. First, never let an unvalidated ID reach a write: check every returned ID against the exact input set and assert the user owns it before any deletion fires. Second, do not show the model raw UUIDs at all. mem0 labels existing memories with small integers ("0", "1", "2") and maps them back afterwards, instructing the model to reuse the input IDs only. An LLM that mutates a store cannot be trusted with identifiers, so validate every one against input and ownership. Memory suggestions shows the full admission flow.

#Silent infrastructure outage

This one is ours too, and it is embarrassing in the way that teaches the most.

A feature produces nothing for weeks and no alarm fires, because "no output" is indistinguishable from "nothing to do." Conversation summaries failed 100 percent for two weeks. The cause was not in the code at all: the API key for the background model provider had never been added to the job runner's production secrets, so every run instant-failed a couple of seconds in, with no loud signal. From the outside, an empty result and a total outage looked identical, and nothing we monitored could tell them apart. Backfilling recovered the stuck jobs once we found it, but the real fix is operational: alert on task failure rate, alert on a feature emitting zero output when it should emit some, and treat secret provisioning as a step in every deploy rather than a thing you remember. Background work will not raise its hand when it dies.

#First-topic dominance

Extraction captures the opening topic of a multi-topic message in rich detail, then drops everything after it. This is a named failure mode in mem0's extraction prompt: the model handles the first subject thoroughly and treats the rest of a long turn as filler, so later facts never become memories. There is no error. The facts are simply not there when you go looking later.

The fix: bias toward over-extraction. mem0's prompt tells the model "when in doubt, extract" (a redundant memory is cheaper than a missing one) and adds a coverage check: for conversations of ten or more messages, expect five to fifteen memories, and if you found fewer than three, re-read. Smart extraction goes deeper.

#Stale and resolved items keep getting re-injected

The agent keeps re-answering questions that were already settled and resurfaces facts that are no longer true. To a vector database, a closed ticket and an open one are the same object: both are semantically similar, and both compete for injection. Similarity has no notion of whether a fact is current or its work is done. One team reported that a single resolution-state field fixed most of their noisy recall: once a chunk is marked resolved, it stops competing even when similarity would pull it in.

A self-inflicted variant is worth flagging because it is so tempting: post-multiplying a reranker's relevance by a recency boost. For a recall tool whose entire job is surfacing old context, that means this week's chatter beats last year's decisive answer, which is exactly backwards. Encode resolution and recency as explicit fields the retriever can filter on (see temporal memory). Do not let a recency multiplier overrule relevance in a tool that exists to remember.

#Confabulation: trusting your own logs

A self-writing agent records actions it never performed, then treats those records as fact in a later session. One builder watched a run "confidently log three actions it never took, then use those logs as context the next session." The entries are not stale; they were never true, inferred from a plausible but wrong read of what happened. Because similarity search has no opinion on whether text describes something real, a confabulated memory passes every retrieval check.

The fix: separate proposing a memory from blessing it. An agent may suggest, but a durable write should be tied to a verifiable ground-truth signal with a real timestamp (a tool-grounded event, a user confirmation, a deterministic validator), never the agent's own narration. The dangerous bug here is not forgetting. It is letting unverified output harden into trusted memory. RAG versus memory and memory suggestions cover the admission gate.

#References