mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
fix: fix max recursion check
This commit is contained in:
parent
a4419c4400
commit
4beb8621a1
2 changed files with 41 additions and 25 deletions
|
|
@ -224,41 +224,56 @@ def json_schema_valid(obj: Any, schema: Dict[str, Any]) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def _basic_json_schema_validate(obj: Any, schema: Dict[str, Any]) -> bool:
|
||||
def _basic_json_schema_validate(
|
||||
obj: Any, schema: Dict[str, Any], max_depth: int = 50
|
||||
) -> bool:
|
||||
"""
|
||||
Basic JSON schema validation without external library.
|
||||
Handles: type, required, properties
|
||||
|
||||
Uses an iterative approach with a stack to avoid recursion limits.
|
||||
max_depth limits nesting to prevent infinite loops from circular schemas.
|
||||
"""
|
||||
# Check type
|
||||
schema_type = schema.get("type")
|
||||
if schema_type:
|
||||
type_map = {
|
||||
"object": dict,
|
||||
"array": list,
|
||||
"string": str,
|
||||
"number": (int, float),
|
||||
"integer": int,
|
||||
"boolean": bool,
|
||||
"null": type(None),
|
||||
}
|
||||
expected_type = type_map.get(schema_type)
|
||||
if expected_type and not isinstance(obj, expected_type):
|
||||
type_map = {
|
||||
"object": dict,
|
||||
"array": list,
|
||||
"string": str,
|
||||
"number": (int, float),
|
||||
"integer": int,
|
||||
"boolean": bool,
|
||||
"null": type(None),
|
||||
}
|
||||
|
||||
# Stack of (obj, schema, depth) tuples to process
|
||||
stack: List[tuple] = [(obj, schema, 0)]
|
||||
|
||||
while stack:
|
||||
current_obj, current_schema, depth = stack.pop()
|
||||
|
||||
# Circuit breaker: stop if we've gone too deep
|
||||
if depth > max_depth:
|
||||
return False
|
||||
|
||||
# Check required fields
|
||||
if isinstance(obj, dict):
|
||||
required = schema.get("required", [])
|
||||
for field in required:
|
||||
if field not in obj:
|
||||
# Check type
|
||||
schema_type = current_schema.get("type")
|
||||
if schema_type:
|
||||
expected_type = type_map.get(schema_type)
|
||||
if expected_type and not isinstance(current_obj, expected_type):
|
||||
return False
|
||||
|
||||
# Check properties
|
||||
properties = schema.get("properties", {})
|
||||
for prop_name, prop_schema in properties.items():
|
||||
if prop_name in obj:
|
||||
if not _basic_json_schema_validate(obj[prop_name], prop_schema):
|
||||
# Check required fields and properties for dicts
|
||||
if isinstance(current_obj, dict):
|
||||
required = current_schema.get("required", [])
|
||||
for field in required:
|
||||
if field not in current_obj:
|
||||
return False
|
||||
|
||||
# Queue property validations
|
||||
properties = current_schema.get("properties", {})
|
||||
for prop_name, prop_schema in properties.items():
|
||||
if prop_name in current_obj:
|
||||
stack.append((current_obj[prop_name], prop_schema, depth + 1))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ IGNORE_FUNCTIONS = [
|
|||
"filter_exceptions_from_params", # max depth set (default 20) to prevent infinite recursion.
|
||||
"__getattr__", # lazy loading pattern in litellm/__init__.py with proper caching to prevent infinite recursion.
|
||||
"_validate_inheritance_chain", # max depth set (default 100) to prevent infinite recursion in policy inheritance validation.
|
||||
"_basic_json_schema_validate", # max depth set.
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue