{"record":{"id":"3af3e38fe8cfa904","repo":"Mintplex-Labs/anything-llm","slug":"would-exceed-char-limit-char-limit","errorCode":null,"errorMessage":"Would exceed ${CHAR_LIMIT} char limit","messagePattern":"Would exceed (.+?) char limit","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"open-computer/services/memory-manager/server.js","lineNumber":65,"sourceCode":"\n// --- API Routes ---\n\napp.get(\"/api/memories\", (_req, res) => {\n  res.json({ entries: readEntries(MEMORY_FILE) });\n});\n\napp.get(\"/api/user\", (_req, res) => {\n  res.json({ entries: readEntries(USER_FILE) });\n});\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);","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/open-computer/services/memory-manager/server.js#L47-L83","documentation":"Returned (HTTP 400) by POST /api/memories when appending the trimmed entry would push the combined length of all existing entries plus delimiters past CHAR_LIMIT (5000, server.js:17). MEMORY.md is injected into the pi agent's system context, so its total size is capped. The append is rejected atomically — nothing is written and the file is left unchanged.","triggerScenarios":"POST /api/memories where current entries joined with ' § ' plus the new entry exceeds 5000 chars; posting a long transcript excerpt when MEMORY.md is already near the cap; repeated small additions accumulating to the limit.","commonSituations":"Pasting whole logs or conversations as a 'memory'; forgetting that the joining delimiter and surrounding spaces count toward the total; agents or scripts appending memories every run until the budget fills.","solutions":["Shorten or summarize the new entry so the combined total fits under 5000 chars","DELETE /api/memories/:index to prune stale entries first, then retry the POST","Compute the budget client-side first: entries.join(' § ').length + 3 + entry.trim().length must be ≤ 5000","Operators who genuinely need more room can raise CHAR_LIMIT, at the cost of a larger agent system prompt"],"exampleFix":"// before\nawait post('/api/memories', {entry: hugeTranscript}); // 400 Would exceed 5000 char limit\n\n// after: check the budget before posting\nconst {entries} = await (await fetch(`${BASE}/api/memories`)).json();\nconst used = entries.join(' § ').length;\nconst entry = hugeTranscript.slice(0, 5000 - used - 3).trim(); // fit the remaining budget\nif (entry) await post('/api/memories', {entry});","handlingStrategy":"validation","validationCode":"const {entries} = await (await fetch(`${BASE}/api/memories`)).json();\nconst used = entries.join(' § ').length; // same DELIMITER + spaces the server joins with\nconst fits = used + 3 + entry.trim().length <= 5000;\nif (!fits) throw new Error('prune old memories first');","typeGuard":null,"tryCatchPattern":"try { await post('/api/memories', {entry}); }\ncatch (e) {\n  if (e.status === 400 && /char limit/.test(e.body?.error ?? '')) {\n    await pruneOldest(); await post('/api/memories', {entry}); // retry once after pruning\n  }\n}","preventionTips":["Show a remaining-characters budget in the UI computed from GET /api/memories","Store summaries, not raw transcripts, as memories","Prune stale entries periodically so the 5000-char budget has headroom"],"tags":["http-400","char-limit","memory-manager","capacity","request-validation"],"backgroundTag":"payload-too-large","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}