litellm - 💡(How to fix) Fix [Bug]: chatgpt/gpt-5.4 returns empty final Responses output, and completion() bridge fails with "Unknown items in responses API response: []" [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#25429Fetched 2026-04-10 03:41:08
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
labeled ×3commented ×1

Error Message

import argparse import importlib.metadata import traceback from dataclasses import asdict, dataclass from typing import Optional

from litellm import completion, responses from litellm.types.llms.openai import ( OutputTextDeltaEvent, ResponseCompletedEvent, ResponsesAPIResponse, ResponsesAPIStreamingResponse, )

@dataclass class NonStreamResult: ok: bool error_type: Optional[str] error_message: Optional[str] status: Optional[str] output_len: Optional[int] output_text_len: Optional[int]

@dataclass class StreamResult: ok: bool error_type: Optional[str] error_message: Optional[str] delta_text_len: Optional[int] completed_status: Optional[str] completed_output_len: Optional[int]

@dataclass class CompletionResult: ok: bool error_type: Optional[str] error_message: Optional[str]

def build_input(prompt: str) -> list[dict]: return [ { "role": "user", "content": [ { "type": "input_text", "text": prompt, } ], } ]

def run_non_stream(model: str, prompt: str) -> NonStreamResult: try: resp: ResponsesAPIResponse = responses( model=model, instructions="You are concise.", input=build_input(prompt), temperature=1.0, stream=False, ) output_text = resp.output_text or "" return NonStreamResult( ok=True, error_type=None, error_message=None, status=resp.status, output_len=len(resp.output), output_text_len=len(output_text), ) except Exception as exc: # noqa: BLE001 return NonStreamResult( ok=False, error_type=type(exc).name, error_message=str(exc), status=None, output_len=None, output_text_len=None, )

def run_stream(model: str, prompt: str) -> StreamResult: try: stream: ResponsesAPIStreamingResponse = responses( model=model, instructions="You are concise.", input=build_input(prompt), temperature=1.0, stream=True, )

    deltas: list[str] = []
    completed_response: ResponsesAPIResponse | None = None

    for chunk in stream:
        if isinstance(chunk, OutputTextDeltaEvent):
            if chunk.delta:
                deltas.append(chunk.delta)
            continue

        if isinstance(chunk, ResponseCompletedEvent):
            completed_response = chunk.response

    return StreamResult(
        ok=True,
        error_type=None,
        error_message=None,
        delta_text_len=len("".join(deltas).strip()),
        completed_status=completed_response.status if completed_response else None,
        completed_output_len=len(completed_response.output) if completed_response else None,
    )
except Exception as exc:  # noqa: BLE001
    return StreamResult(
        ok=False,
        error_type=type(exc).__name__,
        error_message=str(exc),
        delta_text_len=None,
        completed_status=None,
        completed_output_len=None,
    )

def run_completion_bridge(model: str, prompt: str) -> CompletionResult: try: _ = completion( model=model, messages=[{"role": "user", "content": prompt}], temperature=1.0, ) return CompletionResult(ok=True, error_type=None, error_message=None) except Exception as exc: # noqa: BLE001 return CompletionResult( ok=False, error_type=type(exc).name, error_message=str(exc), )

def main() -> int: parser = argparse.ArgumentParser( description=( "Reproduce LiteLLM chatgpt/* bridge issue where non-stream responses can be empty " "while stream delta contains text, and completion() fails in bridge transformation." ) ) parser.add_argument("--model", default="chatgpt/gpt-5.4") parser.add_argument("--prompt", default="Reply with exactly: OK") args = parser.parse_args()

print("litellm_version:", importlib.metadata.version("litellm"))
print("model:", args.model)

non_stream = run_non_stream(args.model, args.prompt)
stream = run_stream(args.model, args.prompt)
bridge = run_completion_bridge(args.model, args.prompt)

print("\nnon_stream:", asdict(non_stream))
print("stream:", asdict(stream))
print("completion_bridge:", asdict(bridge))

bridge_msg = bridge.error_message or ""
bug_signature = (
    non_stream.ok
    and stream.ok
    and non_stream.status == "completed"
    and (non_stream.output_len or 0) == 0
    and (non_stream.output_text_len or 0) == 0
    and (stream.delta_text_len or 0) > 0
)
bridge_signature = "Unknown items in responses API response: []" in bridge_msg

print("\nreproduced_non_stream_empty_vs_stream_delta:", bug_signature)
print("reproduced_completion_bridge_error:", bridge_signature)

if bug_signature or bridge_signature:
    print("\nBUG REPRODUCED")
    return 0

print("\nBUG NOT REPRODUCED (or blocked by auth/network/model differences)")
return 1

if name == "main": try: raise SystemExit(main()) except KeyboardInterrupt: print("Interrupted") raise except Exception: # noqa: BLE001 print("Unexpected fatal error:") traceback.print_exc() raise

Code Example

import argparse
import importlib.metadata
import traceback
from dataclasses import asdict, dataclass
from typing import Optional

from litellm import completion, responses
from litellm.types.llms.openai import (
    OutputTextDeltaEvent,
    ResponseCompletedEvent,
    ResponsesAPIResponse,
    ResponsesAPIStreamingResponse,
)


@dataclass
class NonStreamResult:
    ok: bool
    error_type: Optional[str]
    error_message: Optional[str]
    status: Optional[str]
    output_len: Optional[int]
    output_text_len: Optional[int]


@dataclass
class StreamResult:
    ok: bool
    error_type: Optional[str]
    error_message: Optional[str]
    delta_text_len: Optional[int]
    completed_status: Optional[str]
    completed_output_len: Optional[int]


@dataclass
class CompletionResult:
    ok: bool
    error_type: Optional[str]
    error_message: Optional[str]


def build_input(prompt: str) -> list[dict]:
    return [
        {
            "role": "user",
            "content": [
                {
                    "type": "input_text",
                    "text": prompt,
                }
            ],
        }
    ]


def run_non_stream(model: str, prompt: str) -> NonStreamResult:
    try:
        resp: ResponsesAPIResponse = responses(
            model=model,
            instructions="You are concise.",
            input=build_input(prompt),
            temperature=1.0,
            stream=False,
        )
        output_text = resp.output_text or ""
        return NonStreamResult(
            ok=True,
            error_type=None,
            error_message=None,
            status=resp.status,
            output_len=len(resp.output),
            output_text_len=len(output_text),
        )
    except Exception as exc:  # noqa: BLE001
        return NonStreamResult(
            ok=False,
            error_type=type(exc).__name__,
            error_message=str(exc),
            status=None,
            output_len=None,
            output_text_len=None,
        )


def run_stream(model: str, prompt: str) -> StreamResult:
    try:
        stream: ResponsesAPIStreamingResponse = responses(
            model=model,
            instructions="You are concise.",
            input=build_input(prompt),
            temperature=1.0,
            stream=True,
        )

        deltas: list[str] = []
        completed_response: ResponsesAPIResponse | None = None

        for chunk in stream:
            if isinstance(chunk, OutputTextDeltaEvent):
                if chunk.delta:
                    deltas.append(chunk.delta)
                continue

            if isinstance(chunk, ResponseCompletedEvent):
                completed_response = chunk.response

        return StreamResult(
            ok=True,
            error_type=None,
            error_message=None,
            delta_text_len=len("".join(deltas).strip()),
            completed_status=completed_response.status if completed_response else None,
            completed_output_len=len(completed_response.output) if completed_response else None,
        )
    except Exception as exc:  # noqa: BLE001
        return StreamResult(
            ok=False,
            error_type=type(exc).__name__,
            error_message=str(exc),
            delta_text_len=None,
            completed_status=None,
            completed_output_len=None,
        )


def run_completion_bridge(model: str, prompt: str) -> CompletionResult:
    try:
        _ = completion(
            model=model,
            messages=[{"role": "user", "content": prompt}],
            temperature=1.0,
        )
        return CompletionResult(ok=True, error_type=None, error_message=None)
    except Exception as exc:  # noqa: BLE001
        return CompletionResult(
            ok=False,
            error_type=type(exc).__name__,
            error_message=str(exc),
        )


def main() -> int:
    parser = argparse.ArgumentParser(
        description=(
            "Reproduce LiteLLM chatgpt/* bridge issue where non-stream responses can be empty "
            "while stream delta contains text, and completion() fails in bridge transformation."
        )
    )
    parser.add_argument("--model", default="chatgpt/gpt-5.4")
    parser.add_argument("--prompt", default="Reply with exactly: OK")
    args = parser.parse_args()

    print("litellm_version:", importlib.metadata.version("litellm"))
    print("model:", args.model)

    non_stream = run_non_stream(args.model, args.prompt)
    stream = run_stream(args.model, args.prompt)
    bridge = run_completion_bridge(args.model, args.prompt)

    print("\nnon_stream:", asdict(non_stream))
    print("stream:", asdict(stream))
    print("completion_bridge:", asdict(bridge))

    bridge_msg = bridge.error_message or ""
    bug_signature = (
        non_stream.ok
        and stream.ok
        and non_stream.status == "completed"
        and (non_stream.output_len or 0) == 0
        and (non_stream.output_text_len or 0) == 0
        and (stream.delta_text_len or 0) > 0
    )
    bridge_signature = "Unknown items in responses API response: []" in bridge_msg

    print("\nreproduced_non_stream_empty_vs_stream_delta:", bug_signature)
    print("reproduced_completion_bridge_error:", bridge_signature)

    if bug_signature or bridge_signature:
        print("\nBUG REPRODUCED")
        return 0

    print("\nBUG NOT REPRODUCED (or blocked by auth/network/model differences)")
    return 1


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except KeyboardInterrupt:
        print("Interrupted")
        raise
    except Exception:  # noqa: BLE001
        print("Unexpected fatal error:")
        traceback.print_exc()
        raise

---

litellm_version: 1.83.4
model: chatgpt/gpt-5.4
.venv\Lib\site-packages\pydantic\main.py:464: UserWarning: Pydantic serializer warnings:
  PydanticSerializationUnexpectedValue(Expected `ResponseAPIUsage` - serialized value may not be as expected [field_name='usage', input_value={'completion_tokens': 5, ..., 'video_tokens': None}}, input_type=dict])
  return self.__pydantic_serializer__.to_python(

Give Feedback / Get Help: https://github.com/BerriAI/litellm/issues/new
LiteLLM.Info: If you need to debug this error, use `litellm._turn_on_debug()'.


non_stream: {'ok': True, 'error_type': None, 'error_message': None, 'status': 'completed', 'output_len': 0, 'output_text_len': 0}
stream: {'ok': True, 'error_type': None, 'error_message': None, 'delta_text_len': 2, 'completed_status': 'completed', 'completed_output_len': 0}
completion_bridge: {'ok': False, 'error_type': 'APIConnectionError', 'error_message': 'litellm.APIConnectionError: APIConnectionError: ChatgptException - Unknown items in responses API response: []'}

reproduced_non_stream_empty_vs_stream_delta: True
reproduced_completion_bridge_error: True

BUG REPRODUCED

---
RAW_BUFFERClick to expand / collapse

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

What happened?

Using litellm==1.83.4 with model="chatgpt/gpt-5.4" and ChatGPT subscription auth, I can consistently reproduce two related issues:

  1. litellm.responses(..., stream=False) returns a response with:

    • status="completed"
    • output == []
    • output_text == ""
  2. litellm.responses(..., stream=True) emits OutputTextDeltaEvent text correctly, but the final ResponseCompletedEvent.response is still empty:

    • completed status is "completed"
    • completed response output == []
  3. litellm.completion(...) on the same model then fails in the chat-completions bridge with: litellm.APIConnectionError: APIConnectionError: ChatgptException - Unknown items in responses API response: []

Expected behavior:

  • non-stream Responses calls should return non-empty output / output_text
  • streamed Responses calls should preserve the final assembled output in ResponseCompletedEvent.response
  • completion() should not fail when the upstream request clearly produced text deltas

This looks like a LiteLLM bug in either:

  • final Responses output assembly for the chatgpt/* provider, and/or
  • the completion bridge's handling of empty response.output

Steps to Reproduce

  1. Authenticate with ChatGPT subscription / device flow so chatgpt/gpt-5.4 is available.

  2. Save and run this repro script:

import argparse
import importlib.metadata
import traceback
from dataclasses import asdict, dataclass
from typing import Optional

from litellm import completion, responses
from litellm.types.llms.openai import (
    OutputTextDeltaEvent,
    ResponseCompletedEvent,
    ResponsesAPIResponse,
    ResponsesAPIStreamingResponse,
)


@dataclass
class NonStreamResult:
    ok: bool
    error_type: Optional[str]
    error_message: Optional[str]
    status: Optional[str]
    output_len: Optional[int]
    output_text_len: Optional[int]


@dataclass
class StreamResult:
    ok: bool
    error_type: Optional[str]
    error_message: Optional[str]
    delta_text_len: Optional[int]
    completed_status: Optional[str]
    completed_output_len: Optional[int]


@dataclass
class CompletionResult:
    ok: bool
    error_type: Optional[str]
    error_message: Optional[str]


def build_input(prompt: str) -> list[dict]:
    return [
        {
            "role": "user",
            "content": [
                {
                    "type": "input_text",
                    "text": prompt,
                }
            ],
        }
    ]


def run_non_stream(model: str, prompt: str) -> NonStreamResult:
    try:
        resp: ResponsesAPIResponse = responses(
            model=model,
            instructions="You are concise.",
            input=build_input(prompt),
            temperature=1.0,
            stream=False,
        )
        output_text = resp.output_text or ""
        return NonStreamResult(
            ok=True,
            error_type=None,
            error_message=None,
            status=resp.status,
            output_len=len(resp.output),
            output_text_len=len(output_text),
        )
    except Exception as exc:  # noqa: BLE001
        return NonStreamResult(
            ok=False,
            error_type=type(exc).__name__,
            error_message=str(exc),
            status=None,
            output_len=None,
            output_text_len=None,
        )


def run_stream(model: str, prompt: str) -> StreamResult:
    try:
        stream: ResponsesAPIStreamingResponse = responses(
            model=model,
            instructions="You are concise.",
            input=build_input(prompt),
            temperature=1.0,
            stream=True,
        )

        deltas: list[str] = []
        completed_response: ResponsesAPIResponse | None = None

        for chunk in stream:
            if isinstance(chunk, OutputTextDeltaEvent):
                if chunk.delta:
                    deltas.append(chunk.delta)
                continue

            if isinstance(chunk, ResponseCompletedEvent):
                completed_response = chunk.response

        return StreamResult(
            ok=True,
            error_type=None,
            error_message=None,
            delta_text_len=len("".join(deltas).strip()),
            completed_status=completed_response.status if completed_response else None,
            completed_output_len=len(completed_response.output) if completed_response else None,
        )
    except Exception as exc:  # noqa: BLE001
        return StreamResult(
            ok=False,
            error_type=type(exc).__name__,
            error_message=str(exc),
            delta_text_len=None,
            completed_status=None,
            completed_output_len=None,
        )


def run_completion_bridge(model: str, prompt: str) -> CompletionResult:
    try:
        _ = completion(
            model=model,
            messages=[{"role": "user", "content": prompt}],
            temperature=1.0,
        )
        return CompletionResult(ok=True, error_type=None, error_message=None)
    except Exception as exc:  # noqa: BLE001
        return CompletionResult(
            ok=False,
            error_type=type(exc).__name__,
            error_message=str(exc),
        )


def main() -> int:
    parser = argparse.ArgumentParser(
        description=(
            "Reproduce LiteLLM chatgpt/* bridge issue where non-stream responses can be empty "
            "while stream delta contains text, and completion() fails in bridge transformation."
        )
    )
    parser.add_argument("--model", default="chatgpt/gpt-5.4")
    parser.add_argument("--prompt", default="Reply with exactly: OK")
    args = parser.parse_args()

    print("litellm_version:", importlib.metadata.version("litellm"))
    print("model:", args.model)

    non_stream = run_non_stream(args.model, args.prompt)
    stream = run_stream(args.model, args.prompt)
    bridge = run_completion_bridge(args.model, args.prompt)

    print("\nnon_stream:", asdict(non_stream))
    print("stream:", asdict(stream))
    print("completion_bridge:", asdict(bridge))

    bridge_msg = bridge.error_message or ""
    bug_signature = (
        non_stream.ok
        and stream.ok
        and non_stream.status == "completed"
        and (non_stream.output_len or 0) == 0
        and (non_stream.output_text_len or 0) == 0
        and (stream.delta_text_len or 0) > 0
    )
    bridge_signature = "Unknown items in responses API response: []" in bridge_msg

    print("\nreproduced_non_stream_empty_vs_stream_delta:", bug_signature)
    print("reproduced_completion_bridge_error:", bridge_signature)

    if bug_signature or bridge_signature:
        print("\nBUG REPRODUCED")
        return 0

    print("\nBUG NOT REPRODUCED (or blocked by auth/network/model differences)")
    return 1


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except KeyboardInterrupt:
        print("Interrupted")
        raise
    except Exception:  # noqa: BLE001
        print("Unexpected fatal error:")
        traceback.print_exc()
        raise
  1. Observe
litellm_version: 1.83.4
model: chatgpt/gpt-5.4
.venv\Lib\site-packages\pydantic\main.py:464: UserWarning: Pydantic serializer warnings:
  PydanticSerializationUnexpectedValue(Expected `ResponseAPIUsage` - serialized value may not be as expected [field_name='usage', input_value={'completion_tokens': 5, ..., 'video_tokens': None}}, input_type=dict])
  return self.__pydantic_serializer__.to_python(

Give Feedback / Get Help: https://github.com/BerriAI/litellm/issues/new
LiteLLM.Info: If you need to debug this error, use `litellm._turn_on_debug()'.


non_stream: {'ok': True, 'error_type': None, 'error_message': None, 'status': 'completed', 'output_len': 0, 'output_text_len': 0}
stream: {'ok': True, 'error_type': None, 'error_message': None, 'delta_text_len': 2, 'completed_status': 'completed', 'completed_output_len': 0}
completion_bridge: {'ok': False, 'error_type': 'APIConnectionError', 'error_message': 'litellm.APIConnectionError: APIConnectionError: ChatgptException - Unknown items in responses API response: []'}

reproduced_non_stream_empty_vs_stream_delta: True
reproduced_completion_bridge_error: True

BUG REPRODUCED

Relevant log output

What part of LiteLLM is this about?

SDK (litellm Python package)

What LiteLLM version are you on ?

v1.83.4

Twitter / LinkedIn details

No response

extent analysis

TL;DR

The issue can be addressed by checking the LiteLLM library for updates or reporting the bug to the library maintainers, as the problem seems to be related to the library's handling of responses from the ChatGPT API.

Guidance

  • Verify that the issue is not related to the ChatGPT API itself by checking the API documentation and testing the API directly.
  • Check the LiteLLM library documentation for any known issues or updates that may address the problem.
  • Report the bug to the LiteLLM library maintainers, providing the reproducible script and the observed output.
  • Consider using a different library or API to interact with ChatGPT if the issue is critical and cannot be resolved quickly.

Example

No code example is provided as the issue seems to be related to the LiteLLM library itself, and modifying the library code may not be feasible or recommended.

Notes

The issue may be specific to the chatgpt/gpt-5.4 model or the LiteLLM library version 1.83.4. The reproducible script provided is helpful in identifying the issue, but resolving the issue may require changes to the LiteLLM library or its interaction with the ChatGPT API.

Recommendation

Apply workaround: Report the bug to the LiteLLM library maintainers and wait for a fix or update, or consider using a different library or API to interact with ChatGPT.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

litellm - 💡(How to fix) Fix [Bug]: chatgpt/gpt-5.4 returns empty final Responses output, and completion() bridge fails with "Unknown items in responses API response: []" [1 comments, 2 participants]