{"record":{"id":"5cee2e5e07c51faa","repo":"rohitg00/agentmemory","slug":"content-is-required","errorCode":null,"errorMessage":"content is required","messagePattern":"content is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mcp/standalone.ts","lineNumber":127,"sourceCode":"  agentId?: string;\n  query?: string;\n  limit?: number;\n  format?: string;\n  tokenBudget?: number;\n  memoryIds?: string[];\n  reason?: string;\n}\n\nfunction validate(toolName: string, args: Record<string, unknown>): Validated {\n  if (!IMPLEMENTED_TOOLS.has(toolName)) {\n    throw new Error(`Unknown tool: ${toolName}`);\n  }\n  const v: Validated = { tool: toolName };\n  switch (toolName) {\n    case \"memory_save\": {\n      const content = args[\"content\"];\n      if (typeof content !== \"string\" || !content.trim()) {\n        throw new Error(\"content is required\");\n      }\n      v.content = content;\n      v.type = (args[\"type\"] as string) || \"fact\";\n      v.concepts = normalizeList(args[\"concepts\"]);\n      v.files = normalizeList(args[\"files\"]);\n      // The tool schema exposes project (and now agentId); dropping them\n      // here silently broke project/agent scoping through the stdio\n      // package specifically.\n      if (typeof args[\"project\"] === \"string\" && args[\"project\"].trim()) {\n        v.project = args[\"project\"].trim();\n      }\n      if (typeof args[\"agentId\"] === \"string\" && args[\"agentId\"].trim()) {\n        v.agentId = args[\"agentId\"].trim();\n      }\n      return v;\n    }\n    case \"memory_recall\":\n    case \"memory_smart_search\": {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/rohitg00/agentmemory/blob/e04ba88819c365c9acf9d6661ea802143e728bd6/src/mcp/standalone.ts#L109-L145","documentation":"The memory_save tool requires a non-empty string content argument. validate() rejects calls where content is missing, not a string, or a whitespace-only string, before any storage operation runs.","triggerScenarios":"Calling memory_save with args lacking 'content', content as a non-string (number, object, null), or content: \"   \" (whitespace only).","commonSituations":"LLM tool calls that put the memory text under a wrong key (e.g. 'text' or 'memory') or omit it entirely; programmatic callers passing structured objects instead of strings; empty template fields in automation.","solutions":["Pass a non-empty string as args.content.","Stringify structured payloads with JSON.stringify before calling memory_save.","Check the LLM's argument extraction — map the correct field to 'content'."],"exampleFix":"// before\nawait callTool(\"memory_save\", { text: note });\n// after\nawait callTool(\"memory_save\", { content: String(note).trim() });","handlingStrategy":"validation","validationCode":"function canSave(args) {\n  return typeof args.content === \"string\" && args.content.trim().length > 0;\n}\nif (!canSave(args)) throw new Error(\"memory_save requires non-empty content string\");","typeGuard":"function hasContent(args: Record<string, unknown>): args is { content: string } & Record<string, unknown> {\n  return typeof args.content === \"string\" && args.content.trim().length > 0;\n}","tryCatchPattern":"try {\n  return await callTool(\"memory_save\", args);\n} catch (e) {\n  if (e.message === \"content is required\") {\n    return await callTool(\"memory_save\", { ...args, content: JSON.stringify(args) });\n  }\n  throw e;\n}","preventionTips":["Trim and check content non-empty at every call site wrapper.","For structured data, JSON.stringify into content instead of using sibling keys.","Review LLM tool-use schemas so the model always populates the 'content' field."],"tags":["mcp","validation","arguments"],"backgroundTag":"missing-required-argument","analyzedSha":"e04ba88819c365c9acf9d6661ea802143e728bd6","analyzedAt":"2026-08-30T01:07:40.754Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}