This fixes a critical issue where capitalized values in tool_permission guardrail
configurations (e.g., "Deny" instead of "deny") caused Pydantic validation errors
during proxy startup, leading to repeated initialization failures and latency issues.
Problem:
- Users could save guardrails with capitalized values through UI/API
- Data was written to database without validation (e.g., default_action: "Deny")
- On proxy startup, loading from DB triggered strict Pydantic validation
- ValidationError caused guardrail initialization to fail in a retry loop
- This resulted in startup delays and repeated error logging
Root Cause:
- Write path had no case normalization
- Read path enforced strict lowercase Literal validation
- Asymmetry between write and read caused latent data corruption
Solution:
Added field validators to normalize case before Pydantic validation:
1. ToolPermissionRule.decision ("allow"/"deny")
- Normalizes decision field in rules array
2. ToolPermissionGuardrailConfigModel.default_action ("allow"/"deny")
- Normalizes default fallback action
3. ToolPermissionGuardrailConfigModel.on_disallowed_action ("block"/"rewrite")
- Normalizes disallowed tool behavior
4. ToolPermissionGuardrail.__init__ normalization
- Defensive normalization for direct instantiation
- Ensures normalization regardless of code path
Impact:
- Prevents validation errors during guardrail initialization
- Eliminates startup retry loops and latency issues
- Handles existing database records with capitalized values
- Accepts case-insensitive input from all sources (UI, API, direct calls)
- Fully backward compatible with existing lowercase configurations
Testing:
- Added 3 comprehensive tests for case-insensitive handling
- All 27 existing tests still pass
- Tests verify normalization across all affected fields
Files Changed:
- litellm/types/proxy/guardrails/guardrail_hooks/tool_permission.py
Added @field_validator decorators for case normalization
- litellm/proxy/guardrails/guardrail_hooks/tool_permission.py
Added runtime normalization in __init__ method
- tests/test_litellm/proxy/guardrails/guardrail_hooks/test_tool_permission.py
Added case-insensitive validation tests
Add ability to configure a custom proxy base URL in the Playground UI,
enabling control plane/data plane architecture where:
- Control Plane: Has UI but LLM APIs disabled (DISABLE_LLM_API_ENDPOINTS=true)
- Data Plane: Has LLM APIs but UI disabled
Changes:
- Add "Custom Proxy Base URL" input field in Playground settings
- Persist custom URL in sessionStorage for user convenience
- Modify getProxyBaseUrl() to check sessionStorage first
- All API calls now route to custom URL when configured
This allows users to run the UI on control plane and point API
calls to a separate data plane endpoint.
* refactor: migrate utils.py lazy imports to registry pattern
- Refactored utils.py __getattr__ to use cached registry pattern (similar to __init__.py)
- Added UTILS_MODULE_NAMES tuple and _UTILS_MODULE_IMPORT_MAP to _lazy_imports_registry.py
- Added _get_utils_globals() helper function to _lazy_imports.py
- Added _lazy_import_utils_module() handler function for utils module lazy imports
- Updated _get_lazy_import_registry() to include utils module lazy imports
- Removed redundant _get_utils_globals() from utils.py (now in _lazy_imports.py)
- Added comprehensive tests for utils module lazy imports in test_lazy_imports.py
This refactoring:
- Reduces code duplication (from 670+ lines to ~10 lines in __getattr__)
- Improves maintainability (new lazy imports just need registry entry)
- Maintains consistency with __init__.py lazy import pattern
- All existing functionality preserved and tested
* Fix NameError: get_coroutine_checker not defined in check_coroutine function
* Fix lazy loading for get_coroutine_checker in function_setup and check_coroutine
- Add lazy loading for get_coroutine_checker at start of function_setup to ensure all calls use lazy-loaded version
- Fix check_coroutine function to use lazy loading pattern via getattr
- All direct calls to get_coroutine_checker() now properly use lazy import mechanism
- Added DatadogLLMObsInitParams to TYPES_NAMES in _lazy_imports_registry.py
- Added import map entry for DatadogLLMObsInitParams in _TYPES_IMPORT_MAP
- Moved DatadogLLMObsInitParams import from module level to TYPE_CHECKING block in __init__.py
- Follows existing lazy import patterns for type classes
- Automatically tested by existing test_types_lazy_imports() function
- Keep **kwargs approach (no exec()) for security
- Integrate path traversal validation from main branch
- Add URL encoding for path parameters
- Merge both test suites (edge cases + security tests)
- All 14 tests passing
- Enhanced error messages to show which deployment/credential was used when routing fails
- Added debug logging for pattern-matched deployments to track which deployment was selected
- Added validation warning at startup when multiple wildcard patterns exist for same provider with different credentials
- Helps diagnose intermittent authentication failures caused by non-deterministic wildcard routing
Addresses issue where multiple wildcard deployments (e.g., openai/*) with different credentials
cause intermittent 403 errors due to random credential selection.