{"record":{"id":"71e8e85894afeb52","repo":"666ghj/MiroFish","slug":"zep-search-query-must-not-be-empty","errorCode":null,"errorMessage":"Zep search query must not be empty","messagePattern":"Zep search query must not be empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/app/utils/zep.py","lineNumber":40,"sourceCode":"# Keep request behavior aligned with the zep-cloud 3.25.0 SDK default that\n# MiroFish used before introducing the shared client. This is an internal\n# integration policy, not a deployment setting users need to tune.\nZEP_HTTP_REQUEST_TIMEOUT_SECONDS = 60.0\n# Zep ingestion is asynchronous and may take several minutes. Preserve the\n# original GraphBuilder deadline while keeping it separate from HTTP timeout.\nZEP_INGESTION_WAIT_TIMEOUT_SECONDS = 600\nMAX_ZEP_SEARCH_QUERY_CHARS = 400\nMAX_ZEP_SEARCH_RESULTS = 50\n\n\ndef normalize_zep_search_query(query: Any) -> str:\n    \"\"\"Return a non-empty query within Zep Cloud's endpoint limit.\"\"\"\n\n    if not isinstance(query, str):\n        raise ValueError(\"Zep search query must be a string\")\n    normalized = query.strip()\n    if not normalized:\n        raise ValueError(\"Zep search query must not be empty\")\n    return normalized[:MAX_ZEP_SEARCH_QUERY_CHARS]\n\n\ndef normalize_zep_search_limit(limit: Any) -> int:\n    \"\"\"Clamp a search result limit to the current Zep Cloud contract.\"\"\"\n\n    try:\n        normalized = int(limit)\n    except (TypeError, ValueError) as exc:\n        raise ValueError(\"Zep search limit must be an integer\") from exc\n    if normalized < 1:\n        raise ValueError(\"Zep search limit must be at least 1\")\n    return min(normalized, MAX_ZEP_SEARCH_RESULTS)\n\n\n@lru_cache(maxsize=4)\ndef _cached_zep_client(api_key: str, timeout: float) -> Zep:\n    return Zep(","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/backend/app/utils/zep.py#L22-L58","documentation":"Raised by normalize_zep_search_query in backend/app/utils/zep.py when the query argument is a str but strips to an empty string (only whitespace). The function is a precondition guard for Zep Cloud's graph search endpoint, which rejects blank queries upstream; failing fast here gives a clearer error before any network call. It is a ValueError raised before any HTTP request.","triggerScenarios":"Calling a Zep search wrapper that uses normalize_zep_search_query with query=\"\", query=\"   \", or a string of only newlines/tabs. Any caller forwarding user text or LLM-generated text without a blank check hits this.","commonSituations":"A chat/RAG endpoint where the user submits an empty message; an agent loop passing an LLM-generated search string that happens to be whitespace; a config default of \"\" for a search term.","solutions":["Check query and query.strip() at the caller before invoking the search; return an empty result or re-prompt instead of calling the API.","Validate user-supplied search text at the request boundary (422-style error) so blank input never reaches the Zep layer.","Note the function also truncates to MAX_ZEP_SEARCH_QUERY_CHARS (400); pass pre-trimmed, reasonably sized queries so behavior is predictable."],"exampleFix":"# before\nresults = zep_search(query=user_input)  # user_input = \"   \"\n\n# after\nif not user_input or not user_input.strip():\n    return []\nresults = zep_search(query=user_input.strip())","handlingStrategy":"validation","validationCode":"def is_valid_zep_query(query: Any) -> bool:\n    return isinstance(query, str) and bool(query.strip())","typeGuard":"def is_non_empty_query(query: Any) -> TypeGuard[str]:\n    return isinstance(query, str) and len(query.strip()) > 0","tryCatchPattern":"try:\n    results = zep_search(query=q, limit=10)\nexcept ValueError as e:\n    if \"must not be empty\" in str(e):\n        results = []  # blank query is a no-op\n    else:\n        raise","preventionTips":["Strip and reject blank search text once at the API boundary (422) instead of at the Zep layer.","In agent loops, skip the search step when the generated query is blank.","Pre-trim queries to 400 chars so the truncation behavior is predictable."],"tags":["validation","zep","search","input-validation"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}