Skip to content

Commit 4290c9a

Browse files
committed
fix(review): truncate raw_content in ContentFormatError message
Include truncated raw_content (first 500 chars) in exception message for better debugging while avoiding unbounded output. Full content remains accessible via the raw_content attribute. Update tests to reflect the new message format and add truncation coverage test. Refs: openai#2917
1 parent 24438b0 commit 4290c9a

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

src/openai/_exceptions.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,13 @@ class ContentFormatError(OpenAIError):
179179
def __init__(self, *, raw_content: str, error: Exception, response_format: object | None = None) -> None:
180180
expected_response_format = _response_format_name(response_format)
181181
expected_details = (
182-
f" Expected response format: {expected_response_format}."
183-
if expected_response_format is not None
184-
else ""
182+
f" Expected response format: {expected_response_format}." if expected_response_format is not None else ""
185183
)
184+
truncated_content = raw_content[:500] + "..." if len(raw_content) > 500 else raw_content
186185
super().__init__(
187186
f"Could not parse response content as the response did not match the expected format."
188-
f"{expected_details} Validation error: {_format_parse_error(error)}."
187+
f"{expected_details} Raw content: {truncated_content!r}."
188+
f" Validation error: {_format_parse_error(error)}."
189189
)
190190
self.raw_content = raw_content
191191
self.expected_response_format = expected_response_format
@@ -195,7 +195,12 @@ def __init__(self, *, raw_content: str, error: Exception, response_format: objec
195195
def _response_format_name(response_format: object | None) -> str | None:
196196
if response_format is None:
197197
return None
198-
return cast(str, getattr(response_format, "__name__", None) or getattr(response_format, "__qualname__", None) or repr(response_format))
198+
return cast(
199+
str,
200+
getattr(response_format, "__name__", None)
201+
or getattr(response_format, "__qualname__", None)
202+
or repr(response_format),
203+
)
199204

200205

201206
def _format_parse_error(error: Exception) -> str:

tests/lib/chat/test_completions.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ class Location(BaseModel):
575575
)
576576
assert '{"city": "San' in exc_info.value.raw_content
577577
assert exc_info.value.expected_response_format == "Location"
578-
assert '{"city": "San' not in str(exc_info.value)
578+
assert "Raw content:" in str(exc_info.value)
579579

580580

581581
@pytest.mark.respx(base_url=base_url)
@@ -606,7 +606,21 @@ class Location(BaseModel):
606606
)
607607
assert exc_info.value.raw_content == '{"city": "San Francisco"}'
608608
assert exc_info.value.expected_response_format == "Location"
609-
assert '{"city": "San Francisco"}' not in str(exc_info.value)
609+
assert "Raw content:" in str(exc_info.value)
610+
611+
612+
def test_content_format_error_truncates_raw_content() -> None:
613+
"""Verify raw_content is truncated in the exception message for very large payloads."""
614+
long_content = "x" * 1000
615+
err = openai.ContentFormatError(raw_content=long_content, error=ValueError("bad"), response_format=None)
616+
msg = str(err)
617+
# Full raw_content is preserved on the attribute
618+
assert len(err.raw_content) == 1000
619+
# Message should contain truncated version (500 chars + "...")
620+
assert "xxx..." in msg
621+
assert len(long_content) > 500 # sanity
622+
# Should not contain the full 1000-char string in the message
623+
assert long_content not in msg
610624

611625

612626
@pytest.mark.respx(base_url=base_url)

0 commit comments

Comments
 (0)