{"record":{"id":"a0138881227cafa4","repo":"bytedance/deer-flow","slug":"fact-was-not-stored-because-memory-max-facts-kept","errorCode":null,"errorMessage":"Fact was not stored because memory.max_facts kept higher-confidence facts","messagePattern":"Fact was not stored because memory\\.max_facts kept higher-confidence facts","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"backend/app/gateway/routers/memory.py","lineNumber":334,"sourceCode":"        memory_data, fact_id = await asyncio.to_thread(\n            manager.create_fact,\n            content=request.content,\n            category=request.category,\n            confidence=request.confidence,\n            user_id=_resolve_memory_user_id(http_request),\n        )\n    except NotImplementedError:\n        raise _unsupported_501(manager, \"create fact\") from None\n    except ValueError as exc:\n        raise _map_memory_fact_value_error(exc) from exc\n    except (MemoryConflictError, MemoryCorruptionError) as exc:\n        raise _map_memory_manager_error(exc) from exc\n    except OSError as exc:\n        raise HTTPException(status_code=500, detail=\"Failed to create memory fact.\") from exc\n\n    if fact_id is None:\n        # max_facts cap evicted the new (lower-confidence) fact; it was not stored.\n        raise HTTPException(status_code=409, detail=\"Fact was not stored because memory.max_facts kept higher-confidence facts\")\n    return MemoryResponse(**memory_data)\n\n\n@router.delete(\n    \"/memory/facts/{fact_id}\",\n    response_model=MemoryResponse,\n    response_model_exclude_none=True,\n    summary=\"Delete Memory Fact\",\n    description=\"Delete a single saved memory fact by its fact id.\",\n)\nasync def delete_memory_fact_endpoint(fact_id: str, http_request: Request) -> MemoryResponse:\n    \"\"\"Delete a single fact from memory by fact id.\"\"\"\n    manager = await asyncio.to_thread(get_memory_manager)\n    try:\n        memory_data = await asyncio.to_thread(manager.delete_fact, fact_id, user_id=_resolve_memory_user_id(http_request))\n    except NotImplementedError:\n        raise _unsupported_501(manager, \"delete fact\") from None\n    except KeyError as exc:","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/memory.py#L316-L352","documentation":"409 Conflict returned when create_fact returns a None fact_id: the store is at its memory.max_facts cap, and the newly submitted fact had lower confidence than every stored fact, so it was evicted (not stored) to preserve higher-confidence facts. This is deliberate capacity control, not a crash.","triggerScenarios":"POST /api/memory/facts when the user already has max_facts facts and the new fact's confidence is <= the minimum stored confidence; small max_facts values in config.yaml make this easy to hit during testing.","commonSituations":"Default or low max_facts configured; bulk-importing facts without raising the cap; test suites creating many facts per user; agents saving low-confidence observations on a full store.","solutions":["Raise memory.max_facts in config.yaml if the cap is too small for the workload","Submit the fact with a higher confidence value so it outranks stored facts and earns a slot","Delete lower-value facts first (DELETE /api/memory/facts/{id}) to free capacity"],"exampleFix":"# config.yaml\n# before\nmemory:\n  max_facts: 100\n# after\nmemory:\n  max_facts: 1000\n# or, in the request body:\n# before: {\"content\": \"...\", \"confidence\": 0.2}  (evicted)\n# after:  {\"content\": \"...\", \"confidence\": 0.8}  (stored)","handlingStrategy":"validation","validationCode":"const mem = await getMemory(); const cap = mem.max_facts ?? Infinity; if (Object.keys(mem.facts ?? {}).length >= cap) { const minC = Math.min(...Object.values(mem.facts).map((f: any) => f.confidence ?? 0)); if ((body.confidence ?? 0.5) <= minC) throw new Error('store at max_facts cap and new fact confidence too low — raise cap, delete facts, or raise confidence'); }","typeGuard":"function willFactBeEvicted(currentFactCount: number, maxFacts: number, newConfidence: number, minStoredConfidence: number): boolean { return currentFactCount >= maxFacts && newConfidence <= minStoredConfidence; }","tryCatchPattern":"try { return await createFact(body); } catch (e) { if (e.status === 409 && /max_facts/.test(e.detail)) { return createFact({...body, confidence: bumpConfidence(body.confidence)}); } throw e; }","preventionTips":["Size memory.max_facts to the expected workload in config.yaml","Treat 409 with the max_facts detail as expected capacity control, not an outage","Track fact counts client-side and prune low-value facts proactively"],"tags":["memory","capacity","http-409","configuration"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}