Skip to content

fix: empty guardrails/policies arrays should not trigger enterprise license check - #20567

Merged
2 commits merged into
BerriAI:litellm_oss_staging_02_08_2026from
veeceey:fix/issue-20304-empty-guardrails
Feb 8, 2026
Merged

fix: empty guardrails/policies arrays should not trigger enterprise license check#20567
2 commits merged into
BerriAI:litellm_oss_staging_02_08_2026from
veeceey:fix/issue-20304-empty-guardrails

Conversation

@veeceey

@veeceey veeceey commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #20304

The UI sends empty arrays ([]) for enterprise-only fields (guardrails, policies, logging) even when the user has not configured these features. The backend check updated_kv[field] is not None evaluates to True for empty arrays, triggering a false enterprise license requirement and blocking open-source users from performing basic team operations.

Changes

Backend (litellm/proxy/management_endpoints/common_utils.py):

  • Added and updated_kv[field] != [] and updated_kv[field] != {} guards to both premium and standard metadata field loops in _update_metadata_fields, so empty collections are treated the same as absent/None fields.

UI (ui/litellm-dashboard/src/components/team/team_info.tsx):

  • Changed guardrails, logging, and policies to be conditionally included in the update payload only when they have actual values, instead of defaulting to [].

Tests (tests/test_litellm/proxy/management_endpoints/test_common_utils.py):

  • Added 7 unit tests covering: empty lists, empty dicts, None values, absent fields (no trigger), non-empty lists and values (trigger), and the exact UI payload shape from the bug report.

Test plan

  • pytest tests/test_litellm/proxy/management_endpoints/test_common_utils.py -v -- all 7 tests pass
  • Manual: start proxy without LITELLM_LICENSE, update a team via the UI, verify no 403 error
  • Manual: set enterprise license, configure guardrails on a team, verify it still works

@vercel

vercel Bot commented Feb 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Feb 6, 2026 8:42pm

Request Review

@greptile-apps

greptile-apps Bot commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Overview

Greptile Summary

  • Adjusts backend _update_metadata_fields to ignore empty lists/dicts for metadata/premium fields, preventing false enterprise license checks when UI sends default empty collections.
  • Updates Team settings UI to omit guardrails, logging, and policies from the update payload unless they have non-empty values.
  • Adds regression unit tests for empty/none/absent vs non-empty values to validate premium-check triggering behavior.
  • Net effect: open-source users can update teams without being blocked by UI-default enterprise fields, while non-empty enterprise config still triggers license enforcement.

Confidence Score: 3/5

  • This PR is generally safe to merge, but has a functional edge case and a brittle test import that should be addressed first.
  • Backend change fixes the reported false-positive license enforcement, and UI now avoids sending default empty enterprise arrays. However, treating empty lists/dicts as absent in _update_metadata_fields also prevents intentional clearing of previously-set values via []/{}. The new tests also modify sys.path in a cwd-dependent way, which can fail in CI or import the wrong module.
  • litellm/proxy/management_endpoints/common_utils.py; tests/test_litellm/proxy/management_endpoints/test_common_utils.py

Important Files Changed

Filename Overview
litellm/proxy/management_endpoints/common_utils.py Skips moving metadata fields when updated value is an empty list/dict; fixes false premium checks but also blocks intentionally clearing premium/metadata fields via empty collections.
tests/test_litellm/proxy/management_endpoints/test_common_utils.py Adds regression tests for empty collection payloads; currently uses a cwd-relative sys.path insertion that can break imports in CI and makes tests non-hermetic.
ui/litellm-dashboard/src/components/team/team_info.tsx Omits guardrails/logging/policies from update payload when arrays are empty, preventing backend from interpreting UI defaults as enterprise feature usage.

Sequence Diagram

sequenceDiagram
  participant UI as TeamInfoView (UI)
  participant API as teamUpdateCall (UI networking)
  participant BE as Team update endpoint
  participant CU as _update_metadata_fields
  participant LIC as _premium_user_check

  UI->>API: PUT /team/update (updateData)
  Note over UI: guardrails/logging/policies omitted when empty
  API->>BE: HTTP request with JSON body
  BE->>CU: _update_metadata_fields(updated_kv)
  CU->>CU: For each metadata field
  alt field present && value is not None && not []/{}
    CU->>LIC: _premium_user_check()
    CU->>CU: Move field into updated_kv["metadata"]
  else empty/absent
    CU-->>BE: Skip license check + skip moving field
  end
  BE-->>API: 200 OK (or 403 if premium check fails)
  API-->>UI: Update result
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 237 to 239
for field in LiteLLM_ManagementEndpoint_MetadataFields_Premium:
if field in updated_kv and updated_kv[field] is not None:
if field in updated_kv and updated_kv[field] is not None and updated_kv[field] != [] and updated_kv[field] != {}:
_update_metadata_field(updated_kv=updated_kv, field_name=field)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty update blocked

_update_metadata_fields now skips empty lists/dicts, which prevents the license check but also prevents users from intentionally clearing a previously-set field (e.g., setting policies: [] / metadata.guardrails: [] to remove all policies/guardrails). Since _update_metadata_field moves these keys into metadata, this makes “clear the field” impossible via the update payload.

If clearing should be supported, the condition here needs to distinguish “UI default empty” vs “explicit clear”, or add an explicit clear_* mechanism rather than treating [] as absent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — this was indeed a bug. The empty-collection guard was in the wrong place: it was in _update_metadata_fields (plural), which meant empty lists/dicts were skipped entirely (both the premium check and the field update).

Fixed by moving the empty-collection logic into _update_metadata_field (singular) so that it only bypasses the _premium_user_check() call for empty collections but still proceeds with writing the value into metadata. This means:

  • UI default empty arrays (guardrails: [] sent when nothing is configured) → no premium check, field still written (harmless no-op in metadata)
  • User intentionally clearing a field (guardrails: [] to remove all guardrails) → no premium check, field is cleared in metadata as intended
  • Non-empty values (guardrails: ["my-guardrail"]) → premium check enforced as before

Added test_empty_list_still_updates_metadata and test_empty_dict_still_updates_metadata to verify the clearing behavior.

import pytest
from fastapi import HTTPException

sys.path.insert(0, os.path.abspath("../../../"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fragile import hack

This test mutates sys.path (sys.path.insert(0, os.path.abspath("../../../"))), which is relative to the current working directory, not the test file location. In many CI runners cwd is the repo root, so this resolves to the wrong path and can cause import failures or accidentally import a different litellm.

Prefer relying on pytest’s package discovery (or compute the path from __file__) instead of cwd-relative sys.path edits.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — removed the sys.path.insert(0, os.path.abspath("../../../")) hack along with the unused os, sys, pytest, and FastAPI imports. The test file now relies on standard pytest discovery and uses only the imports it needs (unittest.mock.patch and the function under test).

@veeceey

veeceey commented Feb 6, 2026

Copy link
Copy Markdown
Contributor Author

Ran the tests locally for this PR:

pytest tests/test_litellm/proxy/management_endpoints/test_common_utils.py -v

10 passed in 0.13s

All TestUpdateMetadataFieldsEmptyCollections cases pass — empty lists/dicts/None/absent fields correctly skip the premium check, non-empty values still trigger it, metadata updates still work in both cases, and the typical UI payload scenario is covered.

…icense check (BerriAI#20304)

The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.

Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.

UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.

Fixes BerriAI#20304
…rprise check

Address PR review feedback:

1. Move the empty-collection guard into _update_metadata_field (singular)
   so that empty lists/dicts skip only the premium license check but still
   get written into metadata. This lets users intentionally clear a
   previously-set field (e.g. guardrails: []) without being blocked, while
   the UI's default empty arrays still don't trigger a false enterprise
   error.

2. Remove sys.path hack from test file; use standard imports that work
   with pytest discovery.

3. Add tests verifying that empty collections are moved into metadata
   (field clearing works) even though they bypass the premium check.

Fixes BerriAI#20304
@shivamrawat1

Copy link
Copy Markdown
Collaborator

@greptile re-review this

@greptile-apps

greptile-apps Bot commented Feb 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Overview

Greptile Summary

Fixes issue #20304 where empty arrays for enterprise fields (guardrails, policies, logging) sent by the UI triggered false enterprise license requirements. The fix moves the empty-collection check from _update_metadata_fields into _update_metadata_field, allowing empty arrays to bypass the premium license check while still being written to metadata (enabling users to intentionally clear fields).

Key changes:

  • Backend: Added empty collection guard (!= [] and != {}) in _update_metadata_field before _premium_user_check(), so empty values skip license enforcement but still update metadata
  • UI: Changed to conditionally omit guardrails, logging, and policies from payload when empty (using ?.length > 0 check)
  • Tests: Added 10 comprehensive unit tests covering empty/non-empty lists/dicts, None values, and the exact UI payload structure

The fix correctly addresses the previous review feedback by ensuring users can clear fields (sending [] writes to metadata) without triggering license errors.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is well-designed and addresses the core issue effectively. The logic change is isolated to the premium check condition, preserving all other behavior. The comprehensive test suite (10 tests) validates both the bug fix (empty arrays don't trigger license check) and the enhancement (empty arrays still update metadata for field clearing). Previous review feedback about the inability to clear fields has been properly addressed by moving the check into the singular function. The UI changes are defensive (only send non-empty values), and the backend handles both cases correctly.
  • No files require special attention

Important Files Changed

Filename Overview
litellm/proxy/management_endpoints/common_utils.py Moved empty collection check from _update_metadata_fields into _update_metadata_field to allow field clearing while bypassing premium check for empty values
tests/test_litellm/proxy/management_endpoints/test_common_utils.py Added comprehensive tests covering empty collections bypassing premium check while still updating metadata; removed fragile sys.path imports
ui/litellm-dashboard/src/components/team/team_info.tsx Changed to conditionally exclude empty guardrails, logging, and policies arrays from payload instead of sending empty defaults

Sequence Diagram

sequenceDiagram
    participant UI as UI (team_info.tsx)
    participant Backend as _update_metadata_fields
    participant Field as _update_metadata_field
    participant Check as _premium_user_check

    Note over UI: User updates team settings
    
    alt Empty guardrails/policies
        UI->>Backend: updateData with no guardrails/policies keys
        Note over UI: Only include if length > 0
    else Non-empty values
        UI->>Backend: updateData with guardrails: ["my-guardrail"]
    end

    Backend->>Backend: Loop through premium fields
    
    alt Field exists in updated_kv (top-level)
        Backend->>Field: _update_metadata_field(field_name)
        
        alt Value is [] or {}
            Field->>Field: Skip premium check
            Note over Field: Empty collections bypass license check
            Field->>Field: Move [] to metadata
            Note over Field: Still allows clearing fields
        else Value is non-empty
            Field->>Check: _premium_user_check()
            Note over Check: Enforce license requirement
            Field->>Field: Move value to metadata
        else Value is None
            Field->>Field: Skip update entirely
        end
    end

    Backend-->>UI: Success (no 403 for empty arrays)
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@ghost
ghost changed the base branch from main to litellm_oss_staging_02_08_2026 February 8, 2026 06:22
@ghost
ghost merged commit e24ea28 into BerriAI:litellm_oss_staging_02_08_2026 Feb 8, 2026
7 of 8 checks passed
ghost pushed a commit that referenced this pull request Feb 9, 2026
…TRIBUTES (#20761)

* Add chat completion support for websearch

* Add chat completion tool calls support and response transformation

* Add new methods in chat completion

* Add chat completion tool format

* Add callback for websearch in completion method

* Add test for web search

* Potential fix for code scanning alert no. 4046: Clear-text logging of sensitive information

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Update litellm/integrations/websearch_interception/tools.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20567)

* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20304)

The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.

Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.

UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.

Fixes #20304

* fix: allow clearing fields with empty collections while skipping enterprise check

Address PR review feedback:

1. Move the empty-collection guard into _update_metadata_field (singular)
   so that empty lists/dicts skip only the premium license check but still
   get written into metadata. This lets users intentionally clear a
   previously-set field (e.g. guardrails: []) without being blocked, while
   the UI's default empty arrays still don't trigger a false enterprise
   error.

2. Remove sys.path hack from test file; use standard imports that work
   with pytest discovery.

3. Add tests verifying that empty collections are moved into metadata
   (field clearing works) even though they bypass the premium check.

Fixes #20304

* fix critical CVE vulnerabliltes (#20683)

* fix: add hook to handle db case (#20635)

* Add team policy mapping for zguard (#20608)

* support policy mapping on team key level

* update document

* update document

* address comments

* update document

* add unit test for new feature

* add more test case

* feat: add support for anthropic_messages call type in prompt caching (#19233)

* feat: add support for anthropic_messages call type in prompt caching

* test: move anthropic_messages prompt caching test to main router test file

* add tutorial on using claude code with prompt cache routing

* docs: add SDK proxy authentication (OAuth2/JWT auto-refresh) documentation (#20680)

Adds documentation for the litellm.proxy_auth feature that automatically
obtains and refreshes OAuth2/JWT tokens when connecting to a LiteLLM Proxy.

* Fixes #20582 (#20663)

* fix: show error details instead of Data Not Available for failed requests (#20656)

* fix(ui): add null guard for models in API keys table (#20655)

The VirtualKeysTable crashed when rendering keys with null or undefined
models field. The className expression tried to access .length on null,
throwing a TypeError that broke the entire keys table.

Added Array.isArray() guard before accessing .length on the models value.

Fixes #20611

* Fix: Spend logs pickle error with Pydantic models and redaction (#20685)

* docs: add callback registration optimization to v1.81.9 release notes (#20681)

* docs: add callback registration optimization to v1.81.9 release notes

* Update v1.81.9.md

---------

Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>

* Fix spend logs pickle error with Pydantic models

Replace copy.deepcopy() with Pydantic-safe serialization to avoid
"cannot pickle '_thread.RLock' object" errors when request/response
redaction is enabled.

Changes:
- Add _convert_to_json_serializable_dict() helper that uses
  model_dump() for Pydantic models instead of pickle
- Replace copy.deepcopy() calls in request and response redaction
  paths with the new helper function
- Recursively handles nested dicts, lists, and Pydantic models

Root cause: Pydantic v2 BaseModel instances contain internal
_thread.RLock objects for thread-safety. When copy.deepcopy()
attempts to pickle these objects, it fails because threading
primitives cannot be pickled.

Fixes #20647

* chore: remove unused copy import

Remove unused copy import that was causing lint failure. The copy.deepcopy()
calls were replaced with _convert_to_json_serializable_dict() helper function
in the previous commit, making the copy module no longer needed.

---------

Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>

* fix(vertex_ai): propagate extra_headers anthropic-beta to request body (#20666)

Vertex AI requires Anthropic beta flags in the request body
(anthropic_beta array), not as HTTP headers. The Bedrock handler
already extracts user-specified beta headers from the headers dict,
but the Vertex handler was missing this, causing extra_headers like
interleaved-thinking-2025-05-14 to be silently dropped.

This extracts anthropic-beta values from optional_params extra_headers
and merges them into the anthropic_beta request body field, and also
removes extra_headers from the request body since the parent's
transform_request spreads optional_params into data.

* fix(streaming): preserve interleaved thinking/redacted blocks

* test(streaming): build thinking chunks with typed Delta/StreamingChoices

* Fix video list pagination cursors not encoded with provider metadata

first_id and last_id in the video list response were returned as raw
provider IDs while data[].id was properly wrapped with
encode_video_id_with_provider(). This caused pagination to break when
clients passed unencoded cursors back as the `after` parameter.

- Encode first_id/last_id in transform_video_list_response
- Decode the `after` param in transform_video_list_request via
  extract_original_video_id()
- Add 6 unit tests covering encoding, decoding, passthrough, and
  full round-trip pagination

Fixes #20708

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(responses): preserve streamed tool deltas when id is omitted

* fix(responses): guard ambiguous tool-call index reuse

* Add compaction for vertex ai

* Add all new feat for v1/messages

* Add inference_geo as supported messages param

* Add inference based costing

* Add inference_geo as supported messages param

* Add support for fast param

* Add fast mode for other providers

* Add documentation for Fast Mode

* add missing indexes on VerificationToken table

* Fix structured response of tool call

* Add tests for WebSearch interception with chat completions API

* Add doc for chat completion web search

* Fix: is_web_search_tool_chat_completion

* Fix double json import

* Add new vercel ai anthropic models

* Fix: base_model name for body and deplyment name in URL

* Add output_config as supported param

* Add response schema for vercel ai sonnet 4.5

* handle when litellm_parrams might be none

* Fix : litellm/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py

* fix: Missing return statement for async streaming

* Fix: get_supported_anthropic_messages_params

* Fix mypy issues

* Fix mypy issues

* Add support for extra fields in Generic SSO via GENERIC_USER_EXTRA_ATTRIBUTES

Enables extraction of additional fields from the Generic SSO userinfo endpoint response beyond the standard 8 fields (id, email, name, etc.). Custom handlers can now access these fields via CustomOpenID.extra_fields dict.

Changes:

- Add extra_fields: Optional[Dict[str, Any]] to CustomOpenID type

- Add GENERIC_USER_EXTRA_ATTRIBUTES env var (comma-separated field names)

- Extract specified fields using get_nested_value() with dot notation support

- Add 4 test cases covering basic, nested, and missing field scenarios

- Update custom_sso.py example showing how to access extra_fields

Backward compatible: extra_fields is None when env var not set

* docs: Add documentation for GENERIC_USER_EXTRA_ATTRIBUTES

Document the new GENERIC_USER_EXTRA_ATTRIBUTES environment variable for Generic SSO

- Add to admin_ui_sso.md: explanation and usage examples

- Add to config_settings.md: environment variable reference

- Add to custom_sso.md: code example showing how to access extra_fields

- Includes examples for nested field paths with dot notation

---------

Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Varun Chawla <34209028+veeceey@users.noreply.github.com>
Co-authored-by: Harshit Jain <48647625+Harshit28j@users.noreply.github.com>
Co-authored-by: jwang-gif <j.wang@zscaler.com>
Co-authored-by: nuernber <benjamin.nuernberger@jpl.nasa.gov>
Co-authored-by: Cesar Garcia <128240629+Chesars@users.noreply.github.com>
Co-authored-by: John Lathouwers <john.lathouwers@oracle.com>
Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
Co-authored-by: Elias Högbom Aronsson <elias.aronson@gmail.com>
Co-authored-by: Emerson Gomes <emerson.gomes@thalesgroup.com>
Co-authored-by: tshushan <tshushan@outbrain.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Carlo Alberto Ferraris <cafxx@mercari.com>
@ghost ghost mentioned this pull request Feb 9, 2026
6 tasks
Sameerlite added a commit that referenced this pull request Feb 10, 2026
…TRIBUTES (#20761)

* Add chat completion support for websearch

* Add chat completion tool calls support and response transformation

* Add new methods in chat completion

* Add chat completion tool format

* Add callback for websearch in completion method

* Add test for web search

* Potential fix for code scanning alert no. 4046: Clear-text logging of sensitive information

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Update litellm/integrations/websearch_interception/tools.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20567)

* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20304)

The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.

Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.

UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.

Fixes #20304

* fix: allow clearing fields with empty collections while skipping enterprise check

Address PR review feedback:

1. Move the empty-collection guard into _update_metadata_field (singular)
   so that empty lists/dicts skip only the premium license check but still
   get written into metadata. This lets users intentionally clear a
   previously-set field (e.g. guardrails: []) without being blocked, while
   the UI's default empty arrays still don't trigger a false enterprise
   error.

2. Remove sys.path hack from test file; use standard imports that work
   with pytest discovery.

3. Add tests verifying that empty collections are moved into metadata
   (field clearing works) even though they bypass the premium check.

Fixes #20304

* fix critical CVE vulnerabliltes (#20683)

* fix: add hook to handle db case (#20635)

* Add team policy mapping for zguard (#20608)

* support policy mapping on team key level

* update document

* update document

* address comments

* update document

* add unit test for new feature

* add more test case

* feat: add support for anthropic_messages call type in prompt caching (#19233)

* feat: add support for anthropic_messages call type in prompt caching

* test: move anthropic_messages prompt caching test to main router test file

* add tutorial on using claude code with prompt cache routing

* docs: add SDK proxy authentication (OAuth2/JWT auto-refresh) documentation (#20680)

Adds documentation for the litellm.proxy_auth feature that automatically
obtains and refreshes OAuth2/JWT tokens when connecting to a LiteLLM Proxy.

* Fixes #20582 (#20663)

* fix: show error details instead of Data Not Available for failed requests (#20656)

* fix(ui): add null guard for models in API keys table (#20655)

The VirtualKeysTable crashed when rendering keys with null or undefined
models field. The className expression tried to access .length on null,
throwing a TypeError that broke the entire keys table.

Added Array.isArray() guard before accessing .length on the models value.

Fixes #20611

* Fix: Spend logs pickle error with Pydantic models and redaction (#20685)

* docs: add callback registration optimization to v1.81.9 release notes (#20681)

* docs: add callback registration optimization to v1.81.9 release notes

* Update v1.81.9.md

---------

Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>

* Fix spend logs pickle error with Pydantic models

Replace copy.deepcopy() with Pydantic-safe serialization to avoid
"cannot pickle '_thread.RLock' object" errors when request/response
redaction is enabled.

Changes:
- Add _convert_to_json_serializable_dict() helper that uses
  model_dump() for Pydantic models instead of pickle
- Replace copy.deepcopy() calls in request and response redaction
  paths with the new helper function
- Recursively handles nested dicts, lists, and Pydantic models

Root cause: Pydantic v2 BaseModel instances contain internal
_thread.RLock objects for thread-safety. When copy.deepcopy()
attempts to pickle these objects, it fails because threading
primitives cannot be pickled.

Fixes #20647

* chore: remove unused copy import

Remove unused copy import that was causing lint failure. The copy.deepcopy()
calls were replaced with _convert_to_json_serializable_dict() helper function
in the previous commit, making the copy module no longer needed.

---------

Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>

* fix(vertex_ai): propagate extra_headers anthropic-beta to request body (#20666)

Vertex AI requires Anthropic beta flags in the request body
(anthropic_beta array), not as HTTP headers. The Bedrock handler
already extracts user-specified beta headers from the headers dict,
but the Vertex handler was missing this, causing extra_headers like
interleaved-thinking-2025-05-14 to be silently dropped.

This extracts anthropic-beta values from optional_params extra_headers
and merges them into the anthropic_beta request body field, and also
removes extra_headers from the request body since the parent's
transform_request spreads optional_params into data.

* fix(streaming): preserve interleaved thinking/redacted blocks

* test(streaming): build thinking chunks with typed Delta/StreamingChoices

* Fix video list pagination cursors not encoded with provider metadata

first_id and last_id in the video list response were returned as raw
provider IDs while data[].id was properly wrapped with
encode_video_id_with_provider(). This caused pagination to break when
clients passed unencoded cursors back as the `after` parameter.

- Encode first_id/last_id in transform_video_list_response
- Decode the `after` param in transform_video_list_request via
  extract_original_video_id()
- Add 6 unit tests covering encoding, decoding, passthrough, and
  full round-trip pagination

Fixes #20708

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(responses): preserve streamed tool deltas when id is omitted

* fix(responses): guard ambiguous tool-call index reuse

* Add compaction for vertex ai

* Add all new feat for v1/messages

* Add inference_geo as supported messages param

* Add inference based costing

* Add inference_geo as supported messages param

* Add support for fast param

* Add fast mode for other providers

* Add documentation for Fast Mode

* add missing indexes on VerificationToken table

* Fix structured response of tool call

* Add tests for WebSearch interception with chat completions API

* Add doc for chat completion web search

* Fix: is_web_search_tool_chat_completion

* Fix double json import

* Add new vercel ai anthropic models

* Fix: base_model name for body and deplyment name in URL

* Add output_config as supported param

* Add response schema for vercel ai sonnet 4.5

* handle when litellm_parrams might be none

* Fix : litellm/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py

* fix: Missing return statement for async streaming

* Fix: get_supported_anthropic_messages_params

* Fix mypy issues

* Fix mypy issues

* Add support for extra fields in Generic SSO via GENERIC_USER_EXTRA_ATTRIBUTES

Enables extraction of additional fields from the Generic SSO userinfo endpoint response beyond the standard 8 fields (id, email, name, etc.). Custom handlers can now access these fields via CustomOpenID.extra_fields dict.

Changes:

- Add extra_fields: Optional[Dict[str, Any]] to CustomOpenID type

- Add GENERIC_USER_EXTRA_ATTRIBUTES env var (comma-separated field names)

- Extract specified fields using get_nested_value() with dot notation support

- Add 4 test cases covering basic, nested, and missing field scenarios

- Update custom_sso.py example showing how to access extra_fields

Backward compatible: extra_fields is None when env var not set

* docs: Add documentation for GENERIC_USER_EXTRA_ATTRIBUTES

Document the new GENERIC_USER_EXTRA_ATTRIBUTES environment variable for Generic SSO

- Add to admin_ui_sso.md: explanation and usage examples

- Add to config_settings.md: environment variable reference

- Add to custom_sso.md: code example showing how to access extra_fields

- Includes examples for nested field paths with dot notation

---------

Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Varun Chawla <34209028+veeceey@users.noreply.github.com>
Co-authored-by: Harshit Jain <48647625+Harshit28j@users.noreply.github.com>
Co-authored-by: jwang-gif <j.wang@zscaler.com>
Co-authored-by: nuernber <benjamin.nuernberger@jpl.nasa.gov>
Co-authored-by: Cesar Garcia <128240629+Chesars@users.noreply.github.com>
Co-authored-by: John Lathouwers <john.lathouwers@oracle.com>
Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
Co-authored-by: Elias Högbom Aronsson <elias.aronson@gmail.com>
Co-authored-by: Emerson Gomes <emerson.gomes@thalesgroup.com>
Co-authored-by: tshushan <tshushan@outbrain.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Carlo Alberto Ferraris <cafxx@mercari.com>
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…icense check (BerriAI#20567)

* fix: empty guardrails/policies arrays should not trigger enterprise license check (BerriAI#20304)

The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.

Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.

UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.

Fixes BerriAI#20304

* fix: allow clearing fields with empty collections while skipping enterprise check

Address PR review feedback:

1. Move the empty-collection guard into _update_metadata_field (singular)
   so that empty lists/dicts skip only the premium license check but still
   get written into metadata. This lets users intentionally clear a
   previously-set field (e.g. guardrails: []) without being blocked, while
   the UI's default empty arrays still don't trigger a false enterprise
   error.

2. Remove sys.path hack from test file; use standard imports that work
   with pytest discovery.

3. Add tests verifying that empty collections are moved into metadata
   (field clearing works) even though they bypass the premium check.

Fixes BerriAI#20304
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…TRIBUTES (BerriAI#20761)

* Add chat completion support for websearch

* Add chat completion tool calls support and response transformation

* Add new methods in chat completion

* Add chat completion tool format

* Add callback for websearch in completion method

* Add test for web search

* Potential fix for code scanning alert no. 4046: Clear-text logging of sensitive information

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Update litellm/integrations/websearch_interception/tools.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: empty guardrails/policies arrays should not trigger enterprise license check (BerriAI#20567)

* fix: empty guardrails/policies arrays should not trigger enterprise license check (BerriAI#20304)

The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.

Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.

UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.

Fixes BerriAI#20304

* fix: allow clearing fields with empty collections while skipping enterprise check

Address PR review feedback:

1. Move the empty-collection guard into _update_metadata_field (singular)
   so that empty lists/dicts skip only the premium license check but still
   get written into metadata. This lets users intentionally clear a
   previously-set field (e.g. guardrails: []) without being blocked, while
   the UI's default empty arrays still don't trigger a false enterprise
   error.

2. Remove sys.path hack from test file; use standard imports that work
   with pytest discovery.

3. Add tests verifying that empty collections are moved into metadata
   (field clearing works) even though they bypass the premium check.

Fixes BerriAI#20304

* fix critical CVE vulnerabliltes (BerriAI#20683)

* fix: add hook to handle db case (BerriAI#20635)

* Add team policy mapping for zguard (BerriAI#20608)

* support policy mapping on team key level

* update document

* update document

* address comments

* update document

* add unit test for new feature

* add more test case

* feat: add support for anthropic_messages call type in prompt caching (BerriAI#19233)

* feat: add support for anthropic_messages call type in prompt caching

* test: move anthropic_messages prompt caching test to main router test file

* add tutorial on using claude code with prompt cache routing

* docs: add SDK proxy authentication (OAuth2/JWT auto-refresh) documentation (BerriAI#20680)

Adds documentation for the litellm.proxy_auth feature that automatically
obtains and refreshes OAuth2/JWT tokens when connecting to a LiteLLM Proxy.

* Fixes BerriAI#20582 (BerriAI#20663)

* fix: show error details instead of Data Not Available for failed requests (BerriAI#20656)

* fix(ui): add null guard for models in API keys table (BerriAI#20655)

The VirtualKeysTable crashed when rendering keys with null or undefined
models field. The className expression tried to access .length on null,
throwing a TypeError that broke the entire keys table.

Added Array.isArray() guard before accessing .length on the models value.

Fixes BerriAI#20611

* Fix: Spend logs pickle error with Pydantic models and redaction (BerriAI#20685)

* docs: add callback registration optimization to v1.81.9 release notes (BerriAI#20681)

* docs: add callback registration optimization to v1.81.9 release notes

* Update v1.81.9.md

---------

Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>

* Fix spend logs pickle error with Pydantic models

Replace copy.deepcopy() with Pydantic-safe serialization to avoid
"cannot pickle '_thread.RLock' object" errors when request/response
redaction is enabled.

Changes:
- Add _convert_to_json_serializable_dict() helper that uses
  model_dump() for Pydantic models instead of pickle
- Replace copy.deepcopy() calls in request and response redaction
  paths with the new helper function
- Recursively handles nested dicts, lists, and Pydantic models

Root cause: Pydantic v2 BaseModel instances contain internal
_thread.RLock objects for thread-safety. When copy.deepcopy()
attempts to pickle these objects, it fails because threading
primitives cannot be pickled.

Fixes BerriAI#20647

* chore: remove unused copy import

Remove unused copy import that was causing lint failure. The copy.deepcopy()
calls were replaced with _convert_to_json_serializable_dict() helper function
in the previous commit, making the copy module no longer needed.

---------

Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>

* fix(vertex_ai): propagate extra_headers anthropic-beta to request body (BerriAI#20666)

Vertex AI requires Anthropic beta flags in the request body
(anthropic_beta array), not as HTTP headers. The Bedrock handler
already extracts user-specified beta headers from the headers dict,
but the Vertex handler was missing this, causing extra_headers like
interleaved-thinking-2025-05-14 to be silently dropped.

This extracts anthropic-beta values from optional_params extra_headers
and merges them into the anthropic_beta request body field, and also
removes extra_headers from the request body since the parent's
transform_request spreads optional_params into data.

* fix(streaming): preserve interleaved thinking/redacted blocks

* test(streaming): build thinking chunks with typed Delta/StreamingChoices

* Fix video list pagination cursors not encoded with provider metadata

first_id and last_id in the video list response were returned as raw
provider IDs while data[].id was properly wrapped with
encode_video_id_with_provider(). This caused pagination to break when
clients passed unencoded cursors back as the `after` parameter.

- Encode first_id/last_id in transform_video_list_response
- Decode the `after` param in transform_video_list_request via
  extract_original_video_id()
- Add 6 unit tests covering encoding, decoding, passthrough, and
  full round-trip pagination

Fixes BerriAI#20708


* fix(responses): preserve streamed tool deltas when id is omitted

* fix(responses): guard ambiguous tool-call index reuse

* Add compaction for vertex ai

* Add all new feat for v1/messages

* Add inference_geo as supported messages param

* Add inference based costing

* Add inference_geo as supported messages param

* Add support for fast param

* Add fast mode for other providers

* Add documentation for Fast Mode

* add missing indexes on VerificationToken table

* Fix structured response of tool call

* Add tests for WebSearch interception with chat completions API

* Add doc for chat completion web search

* Fix: is_web_search_tool_chat_completion

* Fix double json import

* Add new vercel ai anthropic models

* Fix: base_model name for body and deplyment name in URL

* Add output_config as supported param

* Add response schema for vercel ai sonnet 4.5

* handle when litellm_parrams might be none

* Fix : litellm/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py

* fix: Missing return statement for async streaming

* Fix: get_supported_anthropic_messages_params

* Fix mypy issues

* Fix mypy issues

* Add support for extra fields in Generic SSO via GENERIC_USER_EXTRA_ATTRIBUTES

Enables extraction of additional fields from the Generic SSO userinfo endpoint response beyond the standard 8 fields (id, email, name, etc.). Custom handlers can now access these fields via CustomOpenID.extra_fields dict.

Changes:

- Add extra_fields: Optional[Dict[str, Any]] to CustomOpenID type

- Add GENERIC_USER_EXTRA_ATTRIBUTES env var (comma-separated field names)

- Extract specified fields using get_nested_value() with dot notation support

- Add 4 test cases covering basic, nested, and missing field scenarios

- Update custom_sso.py example showing how to access extra_fields

Backward compatible: extra_fields is None when env var not set

* docs: Add documentation for GENERIC_USER_EXTRA_ATTRIBUTES

Document the new GENERIC_USER_EXTRA_ATTRIBUTES environment variable for Generic SSO

- Add to admin_ui_sso.md: explanation and usage examples

- Add to config_settings.md: environment variable reference

- Add to custom_sso.md: code example showing how to access extra_fields

- Includes examples for nested field paths with dot notation

---------

Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Varun Chawla <34209028+veeceey@users.noreply.github.com>
Co-authored-by: Harshit Jain <48647625+Harshit28j@users.noreply.github.com>
Co-authored-by: jwang-gif <j.wang@zscaler.com>
Co-authored-by: nuernber <benjamin.nuernberger@jpl.nasa.gov>
Co-authored-by: Cesar Garcia <128240629+Chesars@users.noreply.github.com>
Co-authored-by: John Lathouwers <john.lathouwers@oracle.com>
Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
Co-authored-by: Elias Högbom Aronsson <elias.aronson@gmail.com>
Co-authored-by: Emerson Gomes <emerson.gomes@thalesgroup.com>
Co-authored-by: tshushan <tshushan@outbrain.com>
Co-authored-by: Carlo Alberto Ferraris <cafxx@mercari.com>
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Empty guardrails/policies arrays in UI payload trigger false enterprise license check

2 participants