AttributeError / ValueError
AttributeError: 'NoneType' object has no attribute 'delta' OR ValueError: Unable to parse delta event from stream
Stack trace
Traceback (most recent call last):
File "main.py", line 45, in process_stream
content = response.delta.content
AttributeError: 'NoneType' object has no attribute 'delta'
--- OR ---
Traceback (most recent call last):
File "main.py", line 67, in handle_response_event
text += event.delta.content
ValueError: Unable to parse delta event from stream response. Event type: 'response.done', has no delta. Why it happens
The OpenAI Responses API stream emits multiple event types (response.started, response.content_block_delta, response.done, etc.). Not all events have a delta field: only content block delta events do. If you assume every event has .delta.content without checking the event type first, you get AttributeError. Additionally, some events may have a delta object that is None or incompletely deserialized if the stream frame is truncated or malformed, causing parsing to fail.
Detection
Add logging to inspect the event type and structure before accessing .delta: log(f'Event type: {event.type}, has delta: {hasattr(event, "delta")}') then print(event) to see the raw event. Wrap stream iteration in try/except to catch AttributeError early and log the problematic event.
Causes & fixes
Accessing .delta on non-delta events like response.started or response.done which have no delta field
Check event.type == 'response.content_block_delta' before accessing event.delta: if hasattr(event, 'delta') and event.delta: content = event.delta.content
Delta object exists but .content is None or missing due to stream frame boundaries or incomplete chunks
Guard with if event.delta and event.delta.content: before appending, or use getattr(event.delta, 'content', '') with a fallback empty string
Not properly handling response.done event which marks stream end and has no delta
Check if event.type == 'response.done' and break the stream loop, don't try to extract delta from it
Deserializing stream bytes with incorrect ContentBlockDeltaEvent model, causing delta field to fail parsing
Ensure you're using the correct event model from openai.lib.streaming.responses import ContentBlockDeltaEvent, then safely cast: if isinstance(event, ContentBlockDeltaEvent)
Code: broken vs fixed
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ.get('OPENAI_API_KEY'))
def stream_response():
response = client.responses.create(
model='gpt-4o-mini',
modalities=['text'],
messages=[{'role': 'user', 'content': 'Tell me a short joke'}]
)
for event in response:
# BUG: Not checking event type — assumes all events have .delta
text = event.delta.content # AttributeError if event.type is 'response.done'
print(text, end='', flush=True)
print()
stream_response() import os
from openai import OpenAI
client = OpenAI(api_key=os.environ.get('OPENAI_API_KEY'))
def stream_response():
response = client.responses.create(
model='gpt-4o-mini',
modalities=['text'],
messages=[{'role': 'user', 'content': 'Tell me a short joke'}]
)
for event in response:
# FIX: Check event type and delta existence before accessing
if event.type == 'response.content_block_delta':
if hasattr(event, 'delta') and event.delta and hasattr(event.delta, 'content'):
text = event.delta.content
if text: # Guard against None content
print(text, end='', flush=True)
elif event.type == 'response.done':
# Stream complete, safe to break
break
print()
stream_response() Workaround
If upgrading is not possible, wrap the stream loop in try/except, catch AttributeError, log the event type and raw event data, skip the bad event, and continue with the next one: try: content = event.delta.content except AttributeError: logging.warning(f'Skipped event with no delta: {event.type}'); continue. This allows the stream to complete despite malformed events, though you may lose some content.
Prevention
Structure stream handling as a state machine: maintain a current_event_type variable, check it before accessing event fields, and define allowed field access per event type. Use TypedDict or Pydantic to validate event schemas on deserialization. Always iterate through stream in a try/finally block to ensure cleanup, and log full event objects (via event.model_dump()) when unexpected types are encountered, then file a bug report with OpenAI.