666ghj/MiroFish · error · ValueError
Zep search limit must be at least 1
Error message
Zep search limit must be at least 1
What it means
Raised by normalize_zep_search_limit in backend/app/utils/zep.py when limit converts to an int but is below 1 (0 or negative). Zep Cloud's search API requires limit >= 1, so the guard rejects degenerate values up front. After this check the value is clamped with min(normalized, MAX_ZEP_SEARCH_RESULTS) where MAX_ZEP_SEARCH_RESULTS=50, so anything >= 1 is safe.
Source
Thrown at backend/app/utils/zep.py:52
"""Return a non-empty query within Zep Cloud's endpoint limit."""
if not isinstance(query, str):
raise ValueError("Zep search query must be a string")
normalized = query.strip()
if not normalized:
raise ValueError("Zep search query must not be empty")
return normalized[:MAX_ZEP_SEARCH_QUERY_CHARS]
def normalize_zep_search_limit(limit: Any) -> int:
"""Clamp a search result limit to the current Zep Cloud contract."""
try:
normalized = int(limit)
except (TypeError, ValueError) as exc:
raise ValueError("Zep search limit must be an integer") from exc
if normalized < 1:
raise ValueError("Zep search limit must be at least 1")
return min(normalized, MAX_ZEP_SEARCH_RESULTS)
@lru_cache(maxsize=4)
def _cached_zep_client(api_key: str, timeout: float) -> Zep:
return Zep(
api_key=api_key,
base_url=ZEP_CLOUD_BASE_URL,
timeout=timeout,
)
def get_zep_client(api_key: str | None = None, timeout: float | None = None) -> Zep:
"""Return a process-shared, explicitly configured Zep Cloud client."""
# zep-cloud gives ZEP_API_URL precedence even when base_url is explicit.
# Reject it so this Cloud-only integration cannot silently target a
# self-hosted or compatibility endpoint.View on GitHub (pinned to b5b53acc57)
Solutions
- Coerce non-positive limits to a sensible default before calling: max(limit, 1) or replace 0/negatives with e.g. 10.
- Validate user-supplied limit as an integer in 1..50 at the API boundary and reject out-of-range input there.
- Never use 0 as an 'unset' sentinel for this API; resolve None yourself to a default.
Example fix
# before results = search(query=q, limit=requested) # requested = 0 # after limit = requested if requested and requested > 0 else 10 results = search(query=q, limit=limit)
Defensive patterns
Strategy: validation
Validate before calling
def safe_limit(raw: Any, default: int = 10) -> int:
try:
value = int(raw)
except (TypeError, ValueError):
return default
return value if value >= 1 else default Type guard
def is_positive_limit(value: Any) -> TypeGuard[int]:
if isinstance(value, bool):
return False
try:
return int(value) >= 1
except (TypeError, ValueError):
return False Try / catch
try:
limit = normalize_zep_search_limit(raw)
except ValueError as e:
if "at least 1" in str(e):
limit = 1 # minimum meaningful page
else:
raise Prevention
- Clamp user-supplied limits to 1..50 at the request boundary (values above 50 are silently clamped to 50).
- Do not use 0 as an 'unset' sentinel for limits.
- Validate page-size arithmetic that derives limits — it can underflow to 0 or negative.
When it happens
Trigger: Passing limit=0 (common 'unset' sentinel mistake), negative values from arithmetic (page-size formulas that underflow), or user input "0"/"-5" parsed to int and forwarded.
Common situations: Caller uses 0 to mean 'no preference' expecting a default; a limit computed from page_size/offset math that can reach 0 or go negative on edge inputs.
Related errors
- Zep search limit must be an integer
- Zep batch list cursor did not advance
- graph_id is required
- At least one text chunk is required
- batch_size must be between 1 and 350
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/c83712c37829fdce.
Report an issue: GitHub.