4747_DEFAULT_TIMEOUT = httpx .Timeout (timeout = 5.0 , connect = 5.0 )
4848
4949
50+ def _prepare_request_data_and_content (
51+ data : Optional [Union [dict , str , bytes ]] = None ,
52+ content : Any = None ,
53+ ) -> tuple [Optional [Union [dict , Mapping ]], Any ]:
54+ """
55+ Helper function to route data/content parameters correctly for httpx requests
56+
57+ This prevents httpx DeprecationWarnings that cause memory leaks.
58+
59+ Background:
60+ - httpx shows a DeprecationWarning when you pass bytes/str to `data=`
61+ - It wants you to use `content=` instead for bytes/str
62+ - The warning itself leaks memory when triggered repeatedly
63+
64+ Solution:
65+ - Move bytes/str from `data=` to `content=` before calling build_request
66+ - Keep dicts in `data=` (that's still the correct parameter for dicts)
67+
68+ Args:
69+ data: Request data (can be dict, str, or bytes)
70+ content: Request content (raw bytes/str)
71+
72+ Returns:
73+ Tuple of (request_data, request_content) properly routed for httpx
74+ """
75+ request_data = None
76+ request_content = content
77+
78+ if data is not None :
79+ if isinstance (data , (bytes , str )):
80+ # Bytes/strings belong in content= (only if not already provided)
81+ if content is None :
82+ request_content = data
83+ else :
84+ # dict/Mapping stays in data= parameter
85+ request_data = data
86+
87+ return request_data , request_content
88+
89+
5090def get_ssl_configuration (
5191 ssl_verify : Optional [VerifyTypes ] = None ,
5292) -> Union [bool , str , ssl .SSLContext ]:
@@ -301,33 +341,8 @@ async def post(
301341 if timeout is None :
302342 timeout = self .timeout
303343
304- # ============================================================================
305- # MEMORY LEAK FIX — Prevent httpx DeprecationWarning
306- # ============================================================================
307- # Problem:
308- # httpx shows a DeprecationWarning when you pass bytes/str to `data=`.
309- # It wants you to use `content=` instead.
310- #
311- # Impact:
312- # The warning leaks memory. Preventing the warning fixes the leak.
313- #
314- # Fix:
315- # Move bytes/str from `data=` to `content=` before calling build_request.
316- # Keep dicts in `data=` (that's still correct).
317- # ============================================================================
318-
319- request_data = None
320- request_content = content
321-
322- # Route data parameter to the correct httpx parameter based on type
323- if data is not None :
324- if isinstance (data , (bytes , str )):
325- # Bytes/strings belong in content= (only if not already provided)
326- if content is None :
327- request_content = data
328- else :
329- # dict/Mapping stays in data= parameter
330- request_data = data
344+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
345+ request_data , request_content = _prepare_request_data_and_content (data , content )
331346
332347 req = self .client .build_request (
333348 "POST" ,
@@ -392,19 +407,23 @@ async def post(
392407 async def put (
393408 self ,
394409 url : str ,
395- data : Optional [Union [dict , str ]] = None , # type: ignore
410+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
396411 json : Optional [dict ] = None ,
397412 params : Optional [dict ] = None ,
398413 headers : Optional [dict ] = None ,
399414 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
400415 stream : bool = False ,
416+ content : Any = None ,
401417 ):
402418 try :
403419 if timeout is None :
404420 timeout = self .timeout
405421
422+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
423+ request_data , request_content = _prepare_request_data_and_content (data , content )
424+
406425 req = self .client .build_request (
407- "PUT" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
426+ "PUT" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
408427 )
409428 response = await self .client .send (req )
410429 response .raise_for_status ()
@@ -452,19 +471,23 @@ async def put(
452471 async def patch (
453472 self ,
454473 url : str ,
455- data : Optional [Union [dict , str ]] = None , # type: ignore
474+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
456475 json : Optional [dict ] = None ,
457476 params : Optional [dict ] = None ,
458477 headers : Optional [dict ] = None ,
459478 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
460479 stream : bool = False ,
480+ content : Any = None ,
461481 ):
462482 try :
463483 if timeout is None :
464484 timeout = self .timeout
465485
486+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
487+ request_data , request_content = _prepare_request_data_and_content (data , content )
488+
466489 req = self .client .build_request (
467- "PATCH" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
490+ "PATCH" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
468491 )
469492 response = await self .client .send (req )
470493 response .raise_for_status ()
@@ -512,18 +535,23 @@ async def patch(
512535 async def delete (
513536 self ,
514537 url : str ,
515- data : Optional [Union [dict , str ]] = None , # type: ignore
538+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
516539 json : Optional [dict ] = None ,
517540 params : Optional [dict ] = None ,
518541 headers : Optional [dict ] = None ,
519542 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
520543 stream : bool = False ,
544+ content : Any = None ,
521545 ):
522546 try :
523547 if timeout is None :
524548 timeout = self .timeout
549+
550+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
551+ request_data , request_content = _prepare_request_data_and_content (data , content )
552+
525553 req = self .client .build_request (
526- "DELETE" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
554+ "DELETE" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
527555 )
528556 response = await self .client .send (req , stream = stream )
529557 response .raise_for_status ()
@@ -571,8 +599,11 @@ async def single_connection_post_request(
571599
572600 Used for retrying connection client errors.
573601 """
602+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
603+ request_data , request_content = _prepare_request_data_and_content (data , content )
604+
574605 req = client .build_request (
575- "POST" , url , data = data , json = json , params = params , headers = headers , content = content # type: ignore
606+ "POST" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
576607 )
577608 response = await client .send (req , stream = stream )
578609 response .raise_for_status ()
@@ -826,21 +857,24 @@ def post(
826857 logging_obj : Optional [LiteLLMLoggingObject ] = None ,
827858 ):
828859 try :
860+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
861+ request_data , request_content = _prepare_request_data_and_content (data , content )
862+
829863 if timeout is not None :
830864 req = self .client .build_request (
831865 "POST" ,
832866 url ,
833- data = data , # type: ignore
867+ data = request_data , # type: ignore
834868 json = json ,
835869 params = params ,
836870 headers = headers ,
837871 timeout = timeout ,
838872 files = files ,
839- content = content , # type: ignore
873+ content = request_content , # type: ignore
840874 )
841875 else :
842876 req = self .client .build_request (
843- "POST" , url , data = data , json = json , params = params , headers = headers , files = files , content = content # type: ignore
877+ "POST" , url , data = request_data , json = json , params = params , headers = headers , files = files , content = request_content # type: ignore
844878 )
845879 response = self .client .send (req , stream = stream )
846880 response .raise_for_status ()
@@ -868,21 +902,25 @@ def post(
868902 def patch (
869903 self ,
870904 url : str ,
871- data : Optional [Union [dict , str ]] = None ,
905+ data : Optional [Union [dict , str , bytes ]] = None ,
872906 json : Optional [Union [dict , str ]] = None ,
873907 params : Optional [dict ] = None ,
874908 headers : Optional [dict ] = None ,
875909 stream : bool = False ,
876910 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
911+ content : Any = None ,
877912 ):
878913 try :
914+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
915+ request_data , request_content = _prepare_request_data_and_content (data , content )
916+
879917 if timeout is not None :
880918 req = self .client .build_request (
881- "PATCH" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
919+ "PATCH" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
882920 )
883921 else :
884922 req = self .client .build_request (
885- "PATCH" , url , data = data , json = json , params = params , headers = headers # type: ignore
923+ "PATCH" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
886924 )
887925 response = self .client .send (req , stream = stream )
888926 response .raise_for_status ()
@@ -911,21 +949,25 @@ def patch(
911949 def put (
912950 self ,
913951 url : str ,
914- data : Optional [Union [dict , str ]] = None ,
952+ data : Optional [Union [dict , str , bytes ]] = None ,
915953 json : Optional [Union [dict , str ]] = None ,
916954 params : Optional [dict ] = None ,
917955 headers : Optional [dict ] = None ,
918956 stream : bool = False ,
919957 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
958+ content : Any = None ,
920959 ):
921960 try :
961+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
962+ request_data , request_content = _prepare_request_data_and_content (data , content )
963+
922964 if timeout is not None :
923965 req = self .client .build_request (
924- "PUT" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
966+ "PUT" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
925967 )
926968 else :
927969 req = self .client .build_request (
928- "PUT" , url , data = data , json = json , params = params , headers = headers # type: ignore
970+ "PUT" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
929971 )
930972 response = self .client .send (req , stream = stream )
931973 return response
@@ -941,21 +983,25 @@ def put(
941983 def delete (
942984 self ,
943985 url : str ,
944- data : Optional [Union [dict , str ]] = None , # type: ignore
986+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
945987 json : Optional [dict ] = None ,
946988 params : Optional [dict ] = None ,
947989 headers : Optional [dict ] = None ,
948990 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
949991 stream : bool = False ,
992+ content : Any = None ,
950993 ):
951994 try :
995+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
996+ request_data , request_content = _prepare_request_data_and_content (data , content )
997+
952998 if timeout is not None :
953999 req = self .client .build_request (
954- "DELETE" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
1000+ "DELETE" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
9551001 )
9561002 else :
9571003 req = self .client .build_request (
958- "DELETE" , url , data = data , json = json , params = params , headers = headers # type: ignore
1004+ "DELETE" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
9591005 )
9601006 response = self .client .send (req , stream = stream )
9611007 response .raise_for_status ()
0 commit comments