Files
litellm/CLAUDE.md
T
Ishaan Jaff 503eb2fd4c fix: don't close HTTP/SDK clients on LLMClientCache eviction (#22925)
* fix: don't close HTTP/SDK clients on LLMClientCache eviction

Removing the _remove_key override that eagerly called aclose()/close()
on evicted clients. Evicted clients may still be held by in-flight
streaming requests; closing them causes:

  RuntimeError: Cannot send a request, as the client has been closed.

This is a regression from commit fb72979432. Clients that are no longer
referenced will be garbage-collected naturally. Explicit shutdown cleanup
happens via close_litellm_async_clients().

Fixes production crashes after the 1-hour cache TTL expires.

* test: update LLMClientCache unit tests for no-close-on-eviction behavior

Flip the assertions: evicted clients must NOT be closed. Replace
test_remove_key_closes_async_client → test_remove_key_does_not_close_async_client
and equivalents for sync/eviction paths.

Add test_remove_key_removes_plain_values for non-client cache entries.
Remove test_background_tasks_cleaned_up_after_completion (no more _background_tasks).
Remove test_remove_key_no_event_loop variant that depended on old behavior.

* test: add e2e tests for OpenAI SDK client surviving cache eviction

Add two new e2e tests using real AsyncOpenAI clients:
- test_evicted_openai_sdk_client_stays_usable: verifies size-based eviction
  doesn't close the client
- test_ttl_expired_openai_sdk_client_stays_usable: verifies TTL expiry
  eviction doesn't close the client

Both tests sleep after eviction so any create_task()-based close would
have time to run, making the regression detectable.

Also expand the module docstring to explain why the sleep is required.

* docs(AGENTS.md): add rule — never close HTTP/SDK clients on cache eviction

* docs(CLAUDE.md): add HTTP client cache safety guideline
2026-03-05 12:00:38 -08:00

6.8 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Development Commands

Installation

  • make install-dev - Install core development dependencies
  • make install-proxy-dev - Install proxy development dependencies with full feature set
  • make install-test-deps - Install all test dependencies

Testing

  • make test - Run all tests
  • make test-unit - Run unit tests (tests/test_litellm) with 4 parallel workers
  • make test-integration - Run integration tests (excludes unit tests)
  • pytest tests/ - Direct pytest execution

Code Quality

  • make lint - Run all linting (Ruff, MyPy, Black, circular imports, import safety)
  • make format - Apply Black code formatting
  • make lint-ruff - Run Ruff linting only
  • make lint-mypy - Run MyPy type checking only

Single Test Files

  • poetry run pytest tests/path/to/test_file.py -v - Run specific test file
  • poetry run pytest tests/path/to/test_file.py::test_function -v - Run specific test

Running Scripts

  • poetry run python script.py - Run Python scripts (use for non-test files)

GitHub Issue & PR Templates

When contributing to the project, use the appropriate templates:

Bug Reports (.github/ISSUE_TEMPLATE/bug_report.yml):

  • Describe what happened vs. what you expected
  • Include relevant log output
  • Specify your LiteLLM version

Feature Requests (.github/ISSUE_TEMPLATE/feature_request.yml):

  • Describe the feature clearly
  • Explain the motivation and use case

Pull Requests (.github/pull_request_template.md):

  • Add at least 1 test in tests/litellm/
  • Ensure make test-unit passes

Architecture Overview

LiteLLM is a unified interface for 100+ LLM providers with two main components:

Core Library (litellm/)

  • Main entry point: litellm/main.py - Contains core completion() function
  • Provider implementations: litellm/llms/ - Each provider has its own subdirectory
  • Router system: litellm/router.py + litellm/router_utils/ - Load balancing and fallback logic
  • Type definitions: litellm/types/ - Pydantic models and type hints
  • Integrations: litellm/integrations/ - Third-party observability, caching, logging
  • Caching: litellm/caching/ - Multiple cache backends (Redis, in-memory, S3, etc.)

Proxy Server (litellm/proxy/)

  • Main server: proxy_server.py - FastAPI application
  • Authentication: auth/ - API key management, JWT, OAuth2
  • Database: db/ - Prisma ORM with PostgreSQL/SQLite support
  • Management endpoints: management_endpoints/ - Admin APIs for keys, teams, models
  • Pass-through endpoints: pass_through_endpoints/ - Provider-specific API forwarding
  • Guardrails: guardrails/ - Safety and content filtering hooks
  • UI Dashboard: Served from _experimental/out/ (Next.js build)

Key Patterns

Provider Implementation

  • Providers inherit from base classes in litellm/llms/base.py
  • Each provider has transformation functions for input/output formatting
  • Support both sync and async operations
  • Handle streaming responses and function calling

Error Handling

  • Provider-specific exceptions mapped to OpenAI-compatible errors
  • Fallback logic handled by Router system
  • Comprehensive logging through litellm/_logging.py

Configuration

  • YAML config files for proxy server (see proxy/example_config_yaml/)
  • Environment variables for API keys and settings
  • Database schema managed via Prisma (proxy/schema.prisma)

Development Notes

Code Style

  • Uses Black formatter, Ruff linter, MyPy type checker
  • Pydantic v2 for data validation
  • Async/await patterns throughout
  • Type hints required for all public APIs
  • Avoid imports within methods — place all imports at the top of the file (module-level). Inline imports inside functions/methods make dependencies harder to trace and hurt readability. The only exception is avoiding circular imports where absolutely necessary.

Testing Strategy

  • Unit tests in tests/test_litellm/
  • Integration tests for each provider in tests/llm_translation/
  • Proxy tests in tests/proxy_unit_tests/
  • Load tests in tests/load_tests/
  • Always add tests when adding new entity types or features — if the existing test file covers other entity types, add corresponding tests for the new one

UI / Backend Consistency

  • When wiring a new UI entity type to an existing backend endpoint, verify the backend API contract (single value vs. array, required vs. optional params) and ensure the UI controls match — e.g., use a single-select dropdown when the backend accepts a single value, not a multi-select

Database Migrations

  • Prisma handles schema migrations
  • Migration files auto-generated with prisma migrate dev
  • Always test migrations against both PostgreSQL and SQLite

Proxy database access

  • Do not write raw SQL for proxy DB operations. Use Prisma model methods instead of execute_raw / query_raw.
  • Use the generated client: prisma_client.db.<model> (e.g. litellm_tooltable, litellm_usertable) with .upsert(), .find_many(), .find_unique(), .update(), .update_many() as appropriate. This avoids schema/client drift, keeps code testable with simple mocks, and matches patterns used in spend logs and other proxy code.

Enterprise Features

  • Enterprise-specific code in enterprise/ directory
  • Optional features enabled via environment variables
  • Separate licensing and authentication for enterprise features

HTTP Client Cache Safety

  • Never close HTTP/SDK clients on cache eviction. LLMClientCache._remove_key() must not call close()/aclose() on evicted clients — they may still be used by in-flight requests. Doing so causes RuntimeError: Cannot send a request, as the client has been closed. after the 1-hour TTL expires. Cleanup happens at shutdown via close_litellm_async_clients().

Troubleshooting: DB schema out of sync after proxy restart

litellm-proxy-extras runs prisma migrate deploy on startup using its own bundled migration files, which may lag behind schema changes in the current worktree. Symptoms: Unknown column, Invalid prisma invocation, or missing data on new fields.

Diagnose: Run \d "TableName" in psql and compare against schema.prisma — missing columns confirm the issue.

Fix options:

  1. Create a Prisma migration (permanent) — run prisma migrate dev --name <description> in the worktree. The generated file will be picked up by prisma migrate deploy on next startup.
  2. Apply manually for local devpsql -d litellm -c "ALTER TABLE ... ADD COLUMN IF NOT EXISTS ..." after each proxy start. Fine for dev, not for production.
  3. Update litellm-proxy-extras — if the package is installed from PyPI, its migration directory must include the new file. Either update the package or run the migration manually until the next release ships it.