@@ -205,6 +205,66 @@ def __str__(self) -> str:
205205 return "broken-slice-error-list"
206206
207207
208+ class _BrokenStripMethod (str ):
209+ def strip (self , chars = None ): # type: ignore[override]
210+ _ = chars
211+ raise RuntimeError ("method strip exploded" )
212+
213+
214+ class _BrokenUpperMethod (str ):
215+ def strip (self , chars = None ): # type: ignore[override]
216+ _ = chars
217+ return self
218+
219+ def upper (self ): # type: ignore[override]
220+ raise RuntimeError ("method upper exploded" )
221+
222+
223+ class _BrokenMethodLength (str ):
224+ def strip (self , chars = None ): # type: ignore[override]
225+ _ = chars
226+ return self
227+
228+ def __len__ (self ):
229+ raise RuntimeError ("method length exploded" )
230+
231+
232+ class _BrokenStripUrl (str ):
233+ def strip (self , chars = None ): # type: ignore[override]
234+ _ = chars
235+ raise RuntimeError ("url strip exploded" )
236+
237+
238+ class _BrokenLowerUrl (str ):
239+ def strip (self , chars = None ): # type: ignore[override]
240+ _ = chars
241+ return self
242+
243+ def lower (self ): # type: ignore[override]
244+ raise RuntimeError ("url lower exploded" )
245+
246+
247+ class _BrokenUrlIteration (str ):
248+ def strip (self , chars = None ): # type: ignore[override]
249+ _ = chars
250+ return self
251+
252+ def lower (self ): # type: ignore[override]
253+ return "https://example.com/path"
254+
255+ def __iter__ (self ):
256+ raise RuntimeError ("url iteration exploded" )
257+
258+
259+ class _StringifiesToBrokenSubclass :
260+ class _BrokenString (str ):
261+ def __iter__ (self ):
262+ raise RuntimeError ("fallback string iteration exploded" )
263+
264+ def __str__ (self ) -> str :
265+ return self ._BrokenString ("broken\t fallback\n value" )
266+
267+
208268def test_extract_request_error_context_uses_unknown_when_request_unset ():
209269 method , url = extract_request_error_context (httpx .RequestError ("network down" ))
210270
@@ -663,6 +723,60 @@ def test_format_generic_request_failure_message_supports_memoryview_method_value
663723 assert message == "Request PATCH https://example.com/path failed"
664724
665725
726+ def test_format_generic_request_failure_message_normalizes_method_strip_failures ():
727+ message = format_generic_request_failure_message (
728+ method = _BrokenStripMethod ("get" ),
729+ url = "https://example.com/path" ,
730+ )
731+
732+ assert message == "Request UNKNOWN https://example.com/path failed"
733+
734+
735+ def test_format_generic_request_failure_message_normalizes_method_upper_failures ():
736+ message = format_generic_request_failure_message (
737+ method = _BrokenUpperMethod ("get" ),
738+ url = "https://example.com/path" ,
739+ )
740+
741+ assert message == "Request UNKNOWN https://example.com/path failed"
742+
743+
744+ def test_format_generic_request_failure_message_normalizes_method_length_failures ():
745+ message = format_generic_request_failure_message (
746+ method = _BrokenMethodLength ("get" ),
747+ url = "https://example.com/path" ,
748+ )
749+
750+ assert message == "Request UNKNOWN https://example.com/path failed"
751+
752+
753+ def test_format_generic_request_failure_message_normalizes_url_strip_failures ():
754+ message = format_generic_request_failure_message (
755+ method = "GET" ,
756+ url = _BrokenStripUrl ("https://example.com/path" ),
757+ )
758+
759+ assert message == "Request GET unknown URL failed"
760+
761+
762+ def test_format_generic_request_failure_message_normalizes_url_lower_failures ():
763+ message = format_generic_request_failure_message (
764+ method = "GET" ,
765+ url = _BrokenLowerUrl ("https://example.com/path" ),
766+ )
767+
768+ assert message == "Request GET unknown URL failed"
769+
770+
771+ def test_format_generic_request_failure_message_normalizes_url_iteration_failures ():
772+ message = format_generic_request_failure_message (
773+ method = "GET" ,
774+ url = _BrokenUrlIteration ("https://example.com/path" ),
775+ )
776+
777+ assert message == "Request GET unknown URL failed"
778+
779+
666780def test_format_request_failure_message_truncates_very_long_fallback_urls ():
667781 very_long_url = "https://example.com/" + ("a" * 1200 )
668782 message = format_request_failure_message (
@@ -801,6 +915,15 @@ def test_extract_error_message_sanitizes_control_characters_in_fallback_error_te
801915 assert message == "bad?fallback?text"
802916
803917
918+ def test_extract_error_message_handles_fallback_errors_with_broken_string_subclasses ():
919+ message = extract_error_message (
920+ _DummyResponse (" " , text = " " ),
921+ _StringifiesToBrokenSubclass (),
922+ )
923+
924+ assert message == "<_StringifiesToBrokenSubclass>"
925+
926+
804927def test_extract_error_message_sanitizes_control_characters_in_json_message ():
805928 message = extract_error_message (
806929 _DummyResponse ({"message" : "bad\t json\n message" }),
0 commit comments