{"record":{"id":"ebef3408d7f86680","repo":"ruvnet/ruflo","slug":"query-exceeds-maximum-length-of-max-query-length","errorCode":null,"errorMessage":"Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters","messagePattern":"Query exceeds maximum length of (.+?) characters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts","lineNumber":79,"sourceCode":"const MAX_KEY_LENGTH = 1024;\nconst MAX_VALUE_SIZE = 1024 * 1024; // 1MB\nconst MAX_QUERY_LENGTH = 4096;\n\n// #1425 — single source of truth for the dangerous-character set rejected by\n// validateMemoryInput. Imported by sanitizeMemoryKey so write-side sanitization\n// and read-side rejection can never drift apart (the symmetry bug behind #1884).\nconst DANGEROUS_KEY_CHARS = /[;&|`$(){}[\\]<>!#\\\\\\0]|\\.\\.[/\\\\]/g;\nconst DANGEROUS_KEY_PATTERN = /[;&|`$(){}[\\]<>!#\\\\\\0]|\\.\\.[/\\\\]/;\n\nfunction validateMemoryInput(key?: string, value?: string, query?: string, namespace?: string): void {\n  if (key && key.length > MAX_KEY_LENGTH) {\n    throw new Error(`Key exceeds maximum length of ${MAX_KEY_LENGTH} characters`);\n  }\n  if (value && value.length > MAX_VALUE_SIZE) {\n    throw new Error(`Value exceeds maximum size of ${MAX_VALUE_SIZE} bytes`);\n  }\n  if (query && query.length > MAX_QUERY_LENGTH) {\n    throw new Error(`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`);\n  }\n  // Reject path traversal and shell metacharacters in keys/namespaces (#1425)\n  if (key && DANGEROUS_KEY_PATTERN.test(key)) {\n    throw new Error('Key contains disallowed characters');\n  }\n  if (namespace && DANGEROUS_KEY_PATTERN.test(namespace)) {\n    throw new Error('Namespace contains disallowed characters');\n  }\n}\n\n// #1884 — sanitize a key produced from arbitrary input (markdown headings,\n// frontmatter names, file names) so it survives validateMemoryInput on the\n// read/delete path. Replaces every dangerous char with `_`. Truncates to\n// MAX_KEY_LENGTH so the bound check in validateMemoryInput also passes.\n// Keep this in sync with DANGEROUS_KEY_PATTERN — they share DANGEROUS_KEY_CHARS.\nfunction sanitizeMemoryKey(key: string): string {\n  const safe = key.replace(DANGEROUS_KEY_CHARS, '_');\n  return safe.length > MAX_KEY_LENGTH ? safe.slice(0, MAX_KEY_LENGTH) : safe;","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/ruvnet/ruflo/blob/9c61c86f06b439af2a95085ae9bb0ca839662e41/v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reduce the query to the distinctive keywords or one descriptive sentence — the backend is semantic, so short queries retrieve better","Search with the most informative snippet (e.g. the exception line from a stack trace, ~100-300 chars) rather than the whole log","If you must match long content, store it first via memory_store and search with a short summary query","Guard at the call site: reject or truncate query.slice(0, 4096) before invoking the tool"],"exampleFix":"// before\nawait mcp.callTool('memory_search', { query: fullStackTrace }); // 12k chars -> Query exceeds maximum length\n\n// after\nconst q = fullStackTrace.split('\\n').find(l => l.startsWith('Error')) ?? fullStackTrace.slice(0, 200);\nawait mcp.callTool('memory_search', { query: q });","handlingStrategy":"validation","validationCode":"const MAX_QUERY_LENGTH = 4096;\nfunction prepareSearchQuery(raw: string): string {\n  if (raw.length <= MAX_QUERY_LENGTH) return raw;\n  // semantic search works best with distinctive terms: take the head or the first 'Error' line of a log\n  return raw.slice(0, MAX_QUERY_LENGTH);\n}\n// const query = prepareSearchQuery(userInput);","typeGuard":null,"tryCatchPattern":"try {\n  await memorySearch({ query });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Query exceeds maximum length')) {\n    // shorten to keywords/snippet and retry once with the compact query\n  }\n  throw e;\n}","preventionTips":["Never pass whole documents, transcripts, or stack traces as the search query — extract 1-3 distinctive phrases","Cap query length at the call site (4096 chars) and log when truncation happens so it is visible","For long-content matching, store the content first and search with a short summary","Remember the backend is semantic: shorter, well-chosen queries retrieve better than long dumps"],"tags":["memory","mcp","search","validation","limits","query"],"backgroundTag":"query-too-long","analyzedSha":"9c61c86f06b439af2a95085ae9bb0ca839662e41","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}