{"record":{"id":"547ed31087703cb7","repo":"Mintplex-Labs/anything-llm","slug":"not-found","errorCode":null,"errorMessage":"Not found","messagePattern":"Not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"open-computer/services/memory-manager/server.js","lineNumber":74,"sourceCode":"});\n\napp.post(\"/api/memories\", (req, res) => {\n  const { entry } = req.body;\n  if (!entry || !entry.trim()) return res.status(400).json({ error: \"Empty entry\" });\n  const entries = readEntries(MEMORY_FILE);\n  entries.push(entry.trim());\n  const combined = entries.join(` ${DELIMITER} `);\n  if (combined.length > CHAR_LIMIT) {\n    return res.status(400).json({ error: `Would exceed ${CHAR_LIMIT} char limit` });\n  }\n  writeEntries(MEMORY_FILE, entries);\n  res.json({ entries });\n});\n\napp.delete(\"/api/memories/:index\", (req, res) => {\n  const entries = readEntries(MEMORY_FILE);\n  const idx = parseInt(req.params.index, 10);\n  if (idx < 0 || idx >= entries.length) return res.status(404).json({ error: \"Not found\" });\n  entries.splice(idx, 1);\n  writeEntries(MEMORY_FILE, entries);\n  res.json({ entries });\n});\n\napp.post(\"/api/user\", (req, res) => {\n  const { entry } = req.body;\n  if (!entry || !entry.trim()) return res.status(400).json({ error: \"Empty entry\" });\n  const entries = readEntries(USER_FILE);\n  entries.push(entry.trim());\n  const combined = entries.join(` ${DELIMITER} `);\n  if (combined.length > CHAR_LIMIT) {\n    return res.status(400).json({ error: `Would exceed ${CHAR_LIMIT} char limit` });\n  }\n  writeEntries(USER_FILE, entries);\n  res.json({ entries });\n});\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/open-computer/services/memory-manager/server.js#L56-L92","documentation":"Returned (HTTP 404) by DELETE /api/memories/:index when the parsed index is < 0 or >= entries.length — there is no entry at that position in MEMORY.md. Indexes are positions in the entries array read at request time, so any concurrent deletion, regeneration of the file, or stale list in the client shifts them out of range. (Edge case: a non-numeric index parses to NaN, which slips past both range comparisons and silently deletes nothing — always send a base-10 integer.)","triggerScenarios":"DELETE /api/memories/7 when only 3 entries exist; re-deleting an index after another tab or the /api/review script already modified the file; computing indexes from a GET /api/memories snapshot taken before other deletions; sending '2nd' or '1.5' as the index.","commonSituations":"Two UIs editing memories concurrently (first delete shifts every later index); stale list after the pi review process rewrites MEMORY.md; batch delete loops that do not account for indexes shifting down after each splice.","solutions":["Re-GET /api/memories immediately before each delete and use the fresh index","Treat the 404 as 'already deleted' and refresh your list rather than erroring","For batch deletes, delete from the highest index to the lowest so earlier splices do not shift pending indexes","Always send an integer index (parseInt(idx, 10) on the client) — NaN bypasses the guard and deletes nothing"],"exampleFix":"// before: indexes computed from a stale snapshot\nconst {entries} = await get('/api/memories');\nfor (const i of selected) await del(`/api/memories/${i}`); // 404s as list shrinks\n\n// after: refresh + descending order\nfor (const i of [...selected].sort((a, b) => b - a)) {\n  const res = await del(`/api/memories/${i}`);\n  if (res.status === 404) continue; // someone else already removed it\n}","handlingStrategy":"validation","validationCode":"const {entries} = await (await fetch(`${BASE}/api/memories`)).json();\nconst idx = Number.parseInt(String(rawIndex), 10);\nconst valid = Number.isInteger(idx) && idx >= 0 && idx < entries.length;\nif (!valid) return refreshList();","typeGuard":"function isValidMemoryIndex(idx, entries) {\n  return Number.isInteger(idx) && idx >= 0 && idx < entries.length;\n}","tryCatchPattern":"const res = await del(`${BASE}/api/memories/${idx}`);\nif (res.status === 404) return refreshList(); // someone else already deleted it","preventionTips":["Re-fetch the list immediately before every delete; never trust a stale snapshot","Batch-delete descending (highest index first) so splices do not shift pending indexes","Send integer indexes only — non-numeric params bypass the server guard and silently no-op"],"tags":["http-404","index-out-of-range","memory-manager","concurrency","stale-state"],"backgroundTag":"index-out-of-bounds","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}