openai/openai-python · error · RuntimeError

Encountered a message delta with no previous snapshot

Error message

Encountered a message delta with no previous snapshot

What it means

Raised in accumulate_event when a thread.message.delta event arrives while current_message_snapshot is None. Deltas are incremental patches meant to be applied on top of a thread.message.created snapshot; a delta with no preceding snapshot means the handler missed the creation event (it joined mid-stream, skipped events, or the server sent events out of order).

Source

Thrown at src/openai/lib/streaming/_assistants.py:940

    return None


def accumulate_event(
    *,
    event: AssistantStreamEvent,
    current_message_snapshot: Message | None,
) -> tuple[Message | None, list[MessageContentDelta]]:
    """Returns a tuple of message snapshot and newly created text message deltas"""
    if event.event == "thread.message.created":
        return event.data, []

    new_content: list[MessageContentDelta] = []

    if event.event != "thread.message.delta":
        return current_message_snapshot, []

    if not current_message_snapshot:
        raise RuntimeError("Encountered a message delta with no previous snapshot")

    data = event.data
    if data.delta.content:
        for content_delta in data.delta.content:
            try:
                block = current_message_snapshot.content[content_delta.index]
            except IndexError:
                current_message_snapshot.content.insert(
                    content_delta.index,
                    cast(
                        MessageContent,
                        construct_type(
                            # mypy doesn't allow Content for some reason
                            type_=cast(Any, MessageContent),
                            value=model_dump(content_delta, exclude_unset=True, warnings=False),
                        ),
                    ),
                )

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. Ensure the handler processes every event from the start of the stream (do not drop thread.message.created)
  2. In custom pipelines, call accumulate_event for all events in arrival order and keep the returned snapshot
  3. If resuming a stream, seed current_message_snapshot from the message created event or skip delta accumulation until created arrives
  4. Capture and inspect the event sequence to confirm ordering

Example fix

# before
def on_event(self, event):
    if event.event == "thread.message.delta":
        self.accumulate_event(event)  # created was skipped

# after
def on_event(self, event):
    self.accumulate_event(event)  # process every event in order
Defensive patterns

Strategy: validation

Validate before calling

def can_apply_delta(event, snapshot) -> bool:
    return not (event.event == "thread.message.delta" and snapshot is None)

Type guard

def is_message_delta_with_base(event, current_snapshot) -> bool:
    return event.event == "thread.message.delta" and current_snapshot is not None

Try / catch

try:
    snapshot, _ = accumulate_event(event, snapshot)
except RuntimeError as e:
    if "no previous snapshot" in str(e):
        snapshot = None  # wait for thread.message.created before accumulating

Prevention

When it happens

Trigger: Streaming a run where the thread.message.created event was not processed before thread.message.delta - e.g. a custom handler that filters out or skips creation events, resuming/attaching to an in-flight stream, or manually feeding events into accumulate_event starting from a delta.

Common situations: Custom on_event overrides that selectively forward events to accumulate_event; replaying captured SSE event logs starting mid-stream; server-side event reordering in long runs.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/4752c90703de8cbe. Report an issue: GitHub.