{"record":{"id":"d4896ea5aaa61258","repo":"affaan-m/ECC","slug":"memory-search-query-must-not-contain-control-chara","errorCode":null,"errorMessage":"memory search query must not contain control characters.","messagePattern":"memory search query must not contain control characters\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault.js","lineNumber":596,"sourceCode":"  const start = Math.max(0, (matchIndex < 0 ? 0 : matchIndex) - 60);\n  const prefix = start > 0 ? '…' : '';\n  const suffix = start + maxChars < normalized.length ? '…' : '';\n  return `${prefix}${normalized.slice(start, start + maxChars)}${suffix}`;\n}\n\nfunction summarizeMemory(memory) {\n  return Object.fromEntries(\n    Object.entries(memory).filter(([key]) => key !== 'body')\n  );\n}\n\nfunction searchMemories(query, options = {}) {\n  const normalizedQuery = typeof query === 'string' ? query.trim() : '';\n  if (normalizedQuery.length > MAX_QUERY_CHARS) {\n    throw new Error(`memory search query is too long (maximum ${MAX_QUERY_CHARS} characters).`);\n  }\n  if (hasUnsafeControlCharacters(normalizedQuery)) {\n    throw new Error('memory search query must not contain control characters.');\n  }\n\n  const kinds = options.kinds\n    ? uniqueStrings(options.kinds, {\n      label: 'kinds',\n      limit: MEMORY_KINDS.length,\n      validator: value => validateEnum(value, MEMORY_KINDS, 'memory kind'),\n    })\n    : null;\n  const trust = options.trust\n    ? validateEnum(options.trust, MEMORY_TRUST_STATES, 'memory trust')\n    : null;\n  const targetHarness = options.targetHarness\n    ? validateSlug(options.targetHarness, 'target harness')\n    : null;\n  const limit = Math.max(1, Math.min(Number(options.limit) || 20, MAX_RESULTS));\n  const loaded = readMemoryFiles({ ...options, scopes: options.scopes || options.scope });\n","sourceCodeStart":578,"sourceCodeEnd":614,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/memory-vault.js#L578-L614","documentation":"searchMemories runs hasUnsafeControlCharacters on the trimmed query and refuses queries containing control characters (NUL, ESC, BEL, other C0 controls). Control characters can corrupt terminal output, break tokenization/regex, and be used to smuggle content past naïve filters. The vault rejects them at the API boundary rather than attempt to sanitize.","triggerScenarios":"Calling searchMemories with a query that contains any C0 control character (code points U+0000–U+001F, and typically U+007F DEL). Happens when pasting from a terminal capture that includes escape sequences, when a binary blob is passed as a query, or when programmatic input contains a literal NUL or newline-ish control char.","commonSituations":"Pasting terminal output that includes ANSI escape codes (ESC, CSI); passing a query built from binary data or a buffer that was not decoded as UTF-8 text; a log line containing a NUL byte; copy-paste from a PDF or document carrying invisible control chars.","solutions":["Strip control characters from the query before calling: query.replace(/[\\x00-\\x1f\\x7f]/g, ' ').trim().","If you pasted terminal output, re-copy with 'copy as plain text' or pipe through col -b / sed to strip ANSI sequences.","Sanitize programmatic input: validate the query is a string and filter it through a printable-char whitelist.","Reproduce the offending byte with console.log(JSON.stringify(query)) to see the exact control char, then remove it at the source."],"exampleFix":"// before\nconst results = searchMemories(rawTerminalOutput); // contains ESC[0m etc.\n// after\nconst cleanQuery = rawTerminalOutput.replace(/[\\x00-\\x1f\\x7f]/g, ' ').trim();\nconst results = searchMemories(cleanQuery);","handlingStrategy":"validation","validationCode":"function assertQuerySafe(query) {\n  const q = String(query || '').trim();\n  if (/[\\x00-\\x1f\\x7f]/.test(q)) {\n    throw new Error('memory search query must not contain control characters.');\n  }\n  return q;\n}\n// before searchMemories:\nconst q = assertQuerySafe(rawQuery);","typeGuard":null,"tryCatchPattern":"try { searchMemories(query); }\ncatch (error) {\n  if (/control characters/i.test(error.message)) {\n    const clean = query.replace(/[\\x00-\\x1f\\x7f]/g, ' ').trim();\n    return searchMemories(clean);\n  }\n  throw error;\n}","preventionTips":["Strip ANSI/control chars from pasted terminal output before searching.","Sanitize programmatic input through a printable-char whitelist.","Inspect suspicious queries with console.log(JSON.stringify(query)) to see the exact bytes.","Never pass raw binary/buffer content as a search query."],"tags":["memory-vault","validation","security","search","sanitization"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}