{"record":{"id":"40326f1a06acc12a","repo":"BerriAI/litellm","slug":"invalid-response-object-traceback-format-exc","errorCode":null,"errorMessage":"Invalid response object {traceback.format_exc()}\n\nreceived_args={received_args}","messagePattern":"Invalid response object (.+?)\n\nreceived_args=(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py","lineNumber":877,"sourceCode":"                model_response_object.results = response_object[\"results\"]\n\n            return model_response_object\n    except Exception as e:\n        from litellm.exceptions import APIError\n\n        if isinstance(e, APIError):\n            raise\n\n        received_args: Final = dict(\n            response_object=response_object,\n            model_response_object=model_response_object,\n            response_type=response_type,\n            stream=stream,\n            start_time=start_time,\n            end_time=end_time,\n            convert_tool_call_to_json_mode=convert_tool_call_to_json_mode,\n        )\n        raise Exception(f\"Invalid response object {traceback.format_exc()}\\n\\nreceived_args={received_args}\")\n","sourceCodeStart":859,"sourceCodeEnd":878,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py#L859-L878","documentation":"convert_to_model_response_object wraps its conversion loop in a broad except: APIErrors are re-raised untouched, but any other exception (KeyError on a missing choice field, TypeError, pydantic ValidationError) is re-raised as Exception('Invalid response object <full traceback> received_args={...}'). The original stack trace is embedded in the message, and received_args dumps every argument including the entire response object - so the real cause is the last exception frame in that embedded traceback, and the message can be enormous (and may contain prompt content).","triggerScenarios":"Feeding a response dict whose shape drifts from the chat schema - choice['message'] missing, tool_calls entries lacking index/id/function, a delta-shaped (streaming) object where a message-shaped dict is expected - so a field access throws mid-conversion.","commonSituations":"New/beta provider formats and passthrough endpoints; middleware mutating response dicts; handing ModelResponseStream chunks to the non-streaming converter; mismatched litellm versions between caller and transformer.","solutions":["Read the embedded traceback: the last frame names the exact field access that failed - fix the payload at that key","Diff the received_args dump against the expected schema (choices[].message with tool_calls entries carrying id/type/function)","If the input is a streaming chunk (delta-shaped), use the streaming converters instead","If a standard provider response triggers it, capture a sanitized payload and report with litellm/provider versions"],"exampleFix":"# before\nraw = {\"choices\": [{\"finish_reason\": \"stop\"}]}  # missing 'message'\nresp = convert_to_model_response_object(response_object=raw)  # Exception: Invalid response object ...\n\n# after\nraw = {\"choices\": [{\"message\": {\"role\": \"assistant\", \"content\": \"hi\"}, \"finish_reason\": \"stop\"}]}\nresp = convert_to_model_response_object(response_object=raw)","handlingStrategy":"try-catch","validationCode":"required = all(\n    isinstance(choice, dict) and isinstance(choice.get(\"message\"), dict)\n    for choice in raw.get(\"choices\", [])\n)\nif not required:\n    raise ValueError(f\"response missing choices[].message: {list(raw)}\")","typeGuard":"def is_wellformed_chat_dict(v: object) -> bool:\n    if not isinstance(v, dict) or not isinstance(v.get(\"choices\"), list):\n        return False\n    return all(\n        isinstance(c, dict) and isinstance(c.get(\"message\"), dict) for c in v[\"choices\"]\n    )","tryCatchPattern":"from litellm.exceptions import APIError\n\ntry:\n    resp = convert_to_model_response_object(response_object=raw)\nexcept APIError:\n    raise\nexcept Exception as e:\n    if str(e).startswith(\"Invalid response object\"):\n        # embedded traceback names the failing field; log a truncated, sanitized slice\n        log.error(\"conversion failed: %s\", str(e)[:2000])\n    raise","preventionTips":["The embedded traceback's last frame names the failing key - always read it before guessing","Never log the full received_args payload uncut: it contains the whole response (prompts included)","Pin litellm versions and test provider upgrades against a response-fixture corpus"],"tags":["litellm","response-conversion","debugging","schema-mismatch"],"backgroundTag":"response-conversion-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}