rohitg00/agentmemory · error · Error

mem::search: query must be a non-empty string

Error message

mem::search: query must be a non-empty string

What it means

mem::search requires a query that is a string containing non-whitespace characters. The function normalizes by trimming and throws this validation error up front rather than running a search with an empty query, which would return meaningless results.

Source

Thrown at src/functions/search.ts:384

}

export function registerSearchFunction(sdk: ISdk, kv: StateKV): void {
  sdk.registerFunction(
    'mem::search',
    async (data: {
      query: string
      limit?: number
      project?: string
      cwd?: string
      format?: string
      token_budget?: number
      agentId?: string
    }) => {
      const idx = getSearchIndex()

      // Input validation / normalization.
      if (typeof data?.query !== 'string' || !data.query.trim()) {
        throw new Error('mem::search: query must be a non-empty string')
      }
      const query = data.query.trim()
      const MAX_LIMIT = 100
      let effectiveLimit = 20
      if (data.limit !== undefined) {
        if (!Number.isInteger(data.limit) || data.limit < 1) {
          throw new Error('mem::search: limit must be a positive integer')
        }
        effectiveLimit = Math.min(data.limit, MAX_LIMIT)
      }
      const projectFilter = typeof data.project === 'string' && data.project.trim().length > 0 ? data.project.trim() : undefined
      const cwdFilter = typeof data.cwd === 'string' && data.cwd.trim().length > 0 ? data.cwd.trim() : undefined
      // #817: agent-scope isolation. mem::search backs REST /search,
      // memory_recall and recall_context. Without filtering here a
      // worker booted with AGENT_ID=B + AGENTMEMORY_AGENT_SCOPE=isolated
      // could read A's memories — the cross-agent leak the issue
      // documented. Mirrors the smart-search pattern: wildcard "*"
      // bypasses, explicit agentId pins, isolated mode falls back to

View on GitHub (pinned to e04ba88819)

Solutions

  1. Ensure the payload includes query as a non-empty string.
  2. Guard on the caller side: if (!q?.trim()) skip the search call.
  3. Fix field-name mismatches so the value actually lands in data.query.
  4. Validate/sanitize user input from UIs before forwarding.

Example fix

// before
await trigger({ function_id: 'mem::search', payload: { query: input.q } });
// after
const q = (input.q ?? '').trim();
if (!q) return { results: [] };
await trigger({ function_id: 'mem::search', payload: { query: q } });
Defensive patterns

Strategy: validation

Validate before calling

const q = typeof input.query === 'string' ? input.query.trim() : '';
if (!q) throw new Error('search requires a non-empty query');

Type guard

function isNonEmptyString(v: unknown): v is string {
  return typeof v === 'string' && v.trim().length > 0;
}

Try / catch

try {
  return await trigger({ function_id: 'mem::search', payload: { query } });
} catch (e) {
  if (String(e.message).includes('query must be a non-empty string')) {
    return { results: [] };
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling mem::search (or REST /search / the MCP search tool) with query omitted, null, a number, an empty string '', or a whitespace-only string like ' '.

Common situations: MCP client sending missing/optional query parameter; UI sending the raw value of an empty search box; a refactor renaming the field (e.g. q vs query) so data.query is undefined.

Related errors


AI-assisted analysis of rohitg00/agentmemory@e04ba88819 (2026-08-30). Data as JSON: /api/errors/30e7643e9a6fb9cb. Report an issue: GitHub.