thedotmack/claude-mem · error
observation_record_event: "eventType" is required
Error message
observation_record_event: "eventType" is required
What it means
The observation_record_event MCP tool handler validates its arguments before forwarding them to the server. It throws this error when the 'eventType' argument is absent, not a string, or an empty/whitespace-only string. The library enforces this so events recorded via the observation pipeline always carry a valid event type.
Solutions
- Pass a non-empty string eventType, e.g. { eventType: 'user_prompt_submitted' }
- If the value comes from a variable, default it before calling: args.eventType?.trim() || fallbackEventType
- Check the tool's input schema (required: eventType) in the MCP client to catch it at call-construction time
- Ensure the caller is not passing snake_case job-style aliases; unlike jobId there is no fallback name for eventType
Example fix
// before
await callTool('observation_record_event', { projectId: 'p1', sourceType: 'api' });
// after
await callTool('observation_record_event', { projectId: 'p1', sourceType: 'api', eventType: 'tool_call_completed' }); Defensive patterns
Strategy: validation
Validate before calling
function canRecordEvent(args) {
return typeof args?.eventType === 'string' && args.eventType.trim().length > 0;
}
if (!canRecordEvent(args)) throw new Error('eventType must be a non-empty string before calling observation_record_event'); Type guard
function hasEventType(args: unknown): args is { eventType: string } & Record<string, unknown> {
return typeof (args as any)?.eventType === 'string' && (args as any).eventType.trim().length > 0;
} Try / catch
try {
return await callTool('observation_record_event', args);
} catch (e) {
if (e instanceof Error && e.message.includes('"eventType" is required')) {
console.error('Provide a non-empty eventType, e.g. tool_call_completed');
return null;
}
throw e;
} Prevention
- Always supply a non-empty eventType constant from your event vocabulary
- Validate tool args against the MCP input schema before dispatch
- Never pass user-controlled strings without trimming/emptiness checks
- Keep eventType key spelling consistent (camelCase, not event_type)
When it happens
Trigger: Calling the observation_record_event tool with args missing 'eventType', with eventType set to null/undefined, a non-string value, or a string like '' or ' ' (the handler checks typeof === 'string' && trim().length > 0).
Common situations: LLM clients invoking the tool without the eventType parameter; tool-call argument serialization dropping optional-looking fields; renaming eventType to type/event_type in caller code; template-generated calls where the variable was empty.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- " " is required
- Missing required argument: name
- observation_context: "query" is required
- observation_generation_status: "jobId" is required
- observation_search: "query" is required
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/2f69bc4bfbaf703f.
Report an issue: GitHub.
Appendix: source
Thrown at src/servers/mcp-server.ts:282
serverSessionId?: string | null;
contentSessionId?: string | null;
memorySessionId?: string | null;
platformSource?: string | null;
sourceType?: 'hook' | 'worker' | 'provider' | 'server' | 'api';
eventType: string;
payload?: unknown;
occurredAtEpoch?: number;
generate?: boolean;
}
function normalizeMcpPlatformSource(value: string | null): string | null {
return typeof value === 'string' ? normalizePlatformSource(value) : null;
}
const handleObservationRecordEvent = wrapHandler('observation_record_event', async (args: ObservationRecordEventArgs) => {
const ctx = requireServerForObservationTool('observation_record_event');
if (typeof args?.eventType !== 'string' || args.eventType.trim().length === 0) {
throw new Error('observation_record_event: "eventType" is required');
}
const projectId = args.projectId && args.projectId.trim().length > 0 ? args.projectId : ctx.projectId;
const request: ServerRecordEventRequest = {
projectId,
sourceType: args.sourceType ?? 'api',
eventType: args.eventType,
occurredAtEpoch: typeof args.occurredAtEpoch === 'number' ? args.occurredAtEpoch : Date.now(),
...(args.serverSessionId !== undefined ? { serverSessionId: args.serverSessionId } : {}),
...(args.contentSessionId !== undefined ? { contentSessionId: args.contentSessionId } : {}),
...(args.memorySessionId !== undefined ? { memorySessionId: args.memorySessionId } : {}),
...(args.platformSource !== undefined ? { platformSource: normalizeMcpPlatformSource(args.platformSource) } : {}),
...(args.payload !== undefined ? { payload: args.payload } : {}),
...(args.generate !== undefined ? { generate: args.generate } : {}),
};
const response = await ctx.client.recordEvent(request);
return formatJsonResult(response);
});
View on GitHub (pinned to d8bc9755e7)