ruvnet/ruflo · error

Query exceeds maximum length of

Error message

Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters

What it means

memory_search (and any path feeding a query through validateMemoryInput) throws when the query exceeds MAX_QUERY_LENGTH (4096 characters). The bound keeps the semantic-search embedding input bounded and stops callers smuggling whole prompts through the query field. It is a pre-flight check — no index is touched when it fails.

Solutions

  1. Reduce the query to the distinctive keywords or one descriptive sentence — the backend is semantic, so short queries retrieve better
  2. Search with the most informative snippet (e.g. the exception line from a stack trace, ~100-300 chars) rather than the whole log
  3. If you must match long content, store it first via memory_store and search with a short summary query
  4. Guard at the call site: reject or truncate query.slice(0, 4096) before invoking the tool

Example fix

// before
await mcp.callTool('memory_search', { query: fullStackTrace }); // 12k chars -> Query exceeds maximum length

// after
const q = fullStackTrace.split('\n').find(l => l.startsWith('Error')) ?? fullStackTrace.slice(0, 200);
await mcp.callTool('memory_search', { query: q });
Defensive patterns

Strategy: validation

Validate before calling

const MAX_QUERY_LENGTH = 4096;
function prepareSearchQuery(raw: string): string {
  if (raw.length <= MAX_QUERY_LENGTH) return raw;
  // semantic search works best with distinctive terms: take the head or the first 'Error' line of a log
  return raw.slice(0, MAX_QUERY_LENGTH);
}
// const query = prepareSearchQuery(userInput);

Try / catch

try {
  await memorySearch({ query });
} catch (e) {
  if (e instanceof Error && e.message.includes('Query exceeds maximum length')) {
    // shorten to keywords/snippet and retry once with the compact query
  }
  throw e;
}

Prevention

When it happens

Trigger: memory_search with a query containing an entire document, stack trace, or chat transcript instead of a short phrase; concatenating 'context + question' strings for RAG until they pass 4096 characters.

Common situations: Pasting a full error log into the search query expecting keyword matching; building retrieval queries by string concatenation; agents passing the complete user message as the query.

Related errors


AI-assisted analysis of ruvnet/ruflo@9c61c86f06 (2026-08-18). Data as JSON: /api/errors/ebef3408d7f86680. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts:79

const MAX_KEY_LENGTH = 1024;
const MAX_VALUE_SIZE = 1024 * 1024; // 1MB
const MAX_QUERY_LENGTH = 4096;

// #1425 — single source of truth for the dangerous-character set rejected by
// validateMemoryInput. Imported by sanitizeMemoryKey so write-side sanitization
// and read-side rejection can never drift apart (the symmetry bug behind #1884).
const DANGEROUS_KEY_CHARS = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/g;
const DANGEROUS_KEY_PATTERN = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/;

function validateMemoryInput(key?: string, value?: string, query?: string, namespace?: string): void {
  if (key && key.length > MAX_KEY_LENGTH) {
    throw new Error(`Key exceeds maximum length of ${MAX_KEY_LENGTH} characters`);
  }
  if (value && value.length > MAX_VALUE_SIZE) {
    throw new Error(`Value exceeds maximum size of ${MAX_VALUE_SIZE} bytes`);
  }
  if (query && query.length > MAX_QUERY_LENGTH) {
    throw new Error(`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`);
  }
  // Reject path traversal and shell metacharacters in keys/namespaces (#1425)
  if (key && DANGEROUS_KEY_PATTERN.test(key)) {
    throw new Error('Key contains disallowed characters');
  }
  if (namespace && DANGEROUS_KEY_PATTERN.test(namespace)) {
    throw new Error('Namespace contains disallowed characters');
  }
}

// #1884 — sanitize a key produced from arbitrary input (markdown headings,
// frontmatter names, file names) so it survives validateMemoryInput on the
// read/delete path. Replaces every dangerous char with `_`. Truncates to
// MAX_KEY_LENGTH so the bound check in validateMemoryInput also passes.
// Keep this in sync with DANGEROUS_KEY_PATTERN — they share DANGEROUS_KEY_CHARS.
function sanitizeMemoryKey(key: string): string {
  const safe = key.replace(DANGEROUS_KEY_CHARS, '_');
  return safe.length > MAX_KEY_LENGTH ? safe.slice(0, MAX_KEY_LENGTH) : safe;

View on GitHub (pinned to 9c61c86f06)