mem0ai/mem0 · info · Error
Cancelled
Error message
Cancelled
What it means
Cooperative-cancellation error thrown by the pi-agent-plugin memory tool's 'search' action when the caller-provided AbortSignal is already aborted before the (potentially expensive) Mem0 search request runs. The tool checks signal.aborted at the start of each action to stop work promptly when the user or agent cancels the turn.
Source
Thrown at integrations/pi-agent-plugin/src/memory/tools.ts:57
interface ToolParams {
action: "search" | "add" | "get_all" | "update" | "delete" | "delete_all";
query?: string;
content?: string;
memory_id?: string;
scope?: Scope;
}
export function buildToolExecute(
mem0: MemoryClient,
scopeCtx: ScopeContext,
defaultScope: Scope,
) {
return async (params: ToolParams, signal?: AbortSignal) => {
const scope = params.scope ?? defaultScope;
switch (params.action) {
case "search": {
if (signal?.aborted) throw new Error("Cancelled");
if (!params.query) throw new Error("query is required for search");
const filters = resolveSearchFilters(scope, scopeCtx);
const result = await mem0.search(params.query, { filters });
const memories = result.results ?? [];
return {
content: [{ type: "text" as const, text: truncateOutput(formatMemoryList(memories)) }],
details: { matchCount: memories.length },
};
}
case "add": {
if (signal?.aborted) throw new Error("Cancelled");
if (!params.content) throw new Error("content is required for add");
const addParams = resolveAddParams(scope, scopeCtx);
const result = await mem0.add(
[{ role: "user", content: params.content }],
{ ...addParams, customCategories: DEFAULT_CUSTOM_CATEGORIES },
);View on GitHub (pinned to 001c235229)
Solutions
- Treat as control flow, not a bug: catch it and stop the calling workflow without retrying.
- If cancellation is unexpected, audit where the AbortSignal originates (agent runtime / HTTP request) — something upstream aborted the turn.
- Don't call the tool after awaiting a cancelled operation; check signal.aborted in your own loop first.
Defensive patterns
Strategy: try-catch
Validate before calling
if (signal?.aborted) return { content: [{ type: 'text', text: 'cancelled' }], details: {} }; Try / catch
try {
return await toolExecute(params, signal);
} catch (err) {
if ((err as Error).message === 'Cancelled') return { cancelled: true };
throw err;
} Prevention
- Check signal.aborted in your dispatcher before invoking tools.
- Treat 'Cancelled' as control flow — end the turn, never retry.
When it happens
Trigger: The agent runtime passes an AbortSignal that was aborted (user pressed Esc / cancelled the tool call / turn timeout) and the tool executor still invokes the search action with that signal.
Common situations: User cancels while a tool call is queued; agent framework aborts in-flight tools when a newer turn starts; signal propagated from a request that already timed out.
Related errors
- memory_id is required for update
- HTTP ${resp.status}: ${detail}
- Either memoryId or --all is required
- At least one entity ID is required for deleteEntities.
- Config is not a JSON object
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/38cae32309d1e315.
Report an issue: GitHub.