666ghj/MiroFish · critical · ValueError

ZEP_API_KEY 未配置

Error message

ZEP_API_KEY 未配置

What it means

Raised by get_zep_client in backend/app/utils/zep.py when no API key resolves: the explicit api_key argument, then Config.ZEP_API_KEY, are all empty after .strip(). The Zep Cloud client cannot authenticate without a key, so construction is refused before _cached_zep_client is reached. The message is Chinese ("ZEP_API_KEY is not configured"), matching this project's config-error convention.

Source

Thrown at backend/app/utils/zep.py:76

    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.
    if os.environ.get("ZEP_API_URL"):
        raise ValueError("ZEP_API_URL is unsupported; unset it to use Zep Cloud")

    normalized_key = (api_key or Config.ZEP_API_KEY or "").strip()
    if not normalized_key:
        raise ValueError("ZEP_API_KEY 未配置")

    request_timeout = float(
        timeout if timeout is not None else ZEP_HTTP_REQUEST_TIMEOUT_SECONDS
    )
    if request_timeout <= 0:
        raise ValueError("Zep request timeout must be greater than 0")
    return _cached_zep_client(normalized_key, request_timeout)


def clear_zep_client_cache() -> None:
    """Clear cached clients. Intended for tests and controlled reconfiguration."""

    _cached_zep_client.cache_clear()


def is_retryable_zep_error(error: BaseException) -> bool:
    """Return whether a failed *read* is safe and useful to retry."""

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Set ZEP_API_KEY in .env / process environment to a valid Zep Cloud key from the Zep console.
  2. Verify load order: dotenv/config loading must happen before Config.ZEP_API_KEY is read.
  3. To supply the key programmatically, call get_zep_client(api_key="zep-...") directly — the explicit argument takes priority.

Example fix

# before
client = get_zep_client()  # ZEP_API_KEY unset -> ValueError

# after
# .env: ZEP_API_KEY=zep_...
load_dotenv()
client = get_zep_client()
Defensive patterns

Strategy: validation

Validate before calling

def has_zep_credentials() -> bool:
    return bool((Config.ZEP_API_KEY or "").strip())

Try / catch

try:
    client = get_zep_client()
except ValueError as e:
    if "ZEP_API_KEY" in str(e):
        logger.error("Zep not configured; disabling memory features")
        raise
    raise

Prevention

When it happens

Trigger: Calling get_zep_client() with no argument while Config.ZEP_API_KEY is unset, empty, or whitespace-only; or .env exists but is loaded after Config reads the value.

Common situations: Fresh clone without .env; production deployment where the secret injection (Vault, K8s Secret, CI variable) was skipped; config imported before dotenv.load_dotenv() runs.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/4e37fd3f74c21813. Report an issue: GitHub.