{"record":{"id":"769e7fa0701ea08d","repo":"thedotmack/claude-mem","slug":"observation-add-content-is-required","errorCode":null,"errorMessage":"observation_add: \"content\" is required","messagePattern":"observation_add: \"content\" is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/servers/mcp-server.ts","lineNumber":243,"sourceCode":"      const err = error instanceof Error ? error : new Error(String(error));\n      logger.warn('SYSTEM', `${toolName} failed`, undefined, err);\n      return formatToolError(error);\n    }\n  };\n}\n\ninterface ObservationAddArgs {\n  projectId?: string;\n  serverSessionId?: string | null;\n  kind?: string;\n  content: string;\n  metadata?: Record<string, unknown>;\n}\n\nconst handleObservationAdd = wrapHandler('observation_add', async (args: ObservationAddArgs) => {\n  const ctx = requireServerForObservationTool('observation_add');\n  if (typeof args?.content !== 'string' || args.content.trim().length === 0) {\n    throw new Error('observation_add: \"content\" is required');\n  }\n  const projectId = args.projectId && args.projectId.trim().length > 0 ? args.projectId : ctx.projectId;\n  const request: ServerAddObservationRequest = {\n    projectId,\n    content: args.content,\n    ...(args.serverSessionId !== undefined ? { serverSessionId: args.serverSessionId } : {}),\n    ...(args.kind !== undefined ? { kind: args.kind } : {}),\n    ...(args.metadata !== undefined ? { metadata: args.metadata } : {}),\n  };\n  const response = await ctx.client.addObservation(request);\n  return formatJsonResult(response);\n});\n\ninterface ObservationRecordEventArgs {\n  projectId?: string;\n  serverSessionId?: string | null;\n  contentSessionId?: string | null;\n  memorySessionId?: string | null;","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/servers/mcp-server.ts#L225-L261","documentation":"Validation error inside the observation_add tool handler. After requireServerForObservationTool() passes, the handler checks that args.content is a non-empty trimmed string and throws this plain Error if not. It is an argument-shape guard that runs before the request reaches the server client, so it never causes a network call.","triggerScenarios":"Calling observation_add with content omitted, null, a non-string, or whitespace-only. The MCP schema may mark content as required but JSON-RPC clients can still send malformed arguments (extraProperties is allowed), so this is the last line of defense.","commonSituations":"LLM-driven MCP client omits content because it only passed metadata; an automation sends { kind: 'note' } with no content; content is an empty string from a templating bug; caller confused observation_add (free text) with observation_record_event (eventType).","solutions":["Provide a non-empty content string in the tool call arguments.","If you meant to record a typed event rather than free text, use observation_record_event with eventType instead.","Add a client-side check that trims content before calling the tool so the error never fires."],"exampleFix":"// before\nawait tools.observation_add({ kind: 'note', metadata: { x: 1 } });\n// throws 'observation_add: \"content\" is required'\n\n// after\nawait tools.observation_add({\n  content: 'Refactored ModeManager.loadMode to fall back to code mode.',\n  kind: 'note',\n});","handlingStrategy":"validation","validationCode":"function validObservationContent(args: unknown): args is { content: string } {\n  return typeof (args as any)?.content === 'string' && (args as any).content.trim().length > 0;\n}\nif (!validObservationContent(args)) {\n  return { content: [{ type: 'text', text: 'content is required' }], isError: true };\n}","typeGuard":"function isObservationAddArgs(v: unknown): v is { content: string; kind?: string; metadata?: Record<string, unknown> } {\n  return typeof (v as any)?.content === 'string' && (v as any).content.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Trim and length-check content on the caller side before invoking observation_add.","Distinguish observation_add (free text) from observation_record_event (typed event) in tool docs.","Include content in MCP tool examples so LLM clients always supply it."],"tags":["mcp","validation","observation-tools"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}