{"record":{"id":"58deaf4e1947d032","repo":"BerriAI/litellm","slug":"batch-record-for-v1-responses-is-missing-required","errorCode":null,"errorMessage":"Batch record for /v1/responses is missing required `input` field: model={openai_request_body.get('model', '')}","messagePattern":"Batch record for /v1/responses is missing required `input` field: model=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/bedrock/files/transformation.py","lineNumber":735,"sourceCode":"    @staticmethod\n    def _transform_responses_body_to_chat_body(openai_request_body: _OpenAIBatchRecordBody) -> Mapping[str, object]:\n        \"\"\"\n        Rewrite an OpenAI `/v1/responses` batch body as a Chat Completions body.\n\n        Delegates to the same Responses-to-Chat bridge the real-time path uses\n        for providers without a native Responses API (which is every Bedrock\n        model), so `input`, `instructions`, `max_output_tokens` and the tool\n        params translate identically in batch and real time. The bridge always\n        emits a `tools` key; an empty one is dropped rather than shipped as an\n        empty array inside `modelInput`.\n        \"\"\"\n        from litellm.responses.litellm_completion_transformation.transformation import (\n            LiteLLMCompletionResponsesConfig,\n        )\n\n        responses_input: Final = openai_request_body.get(\"input\")\n        if responses_input is None:\n            raise ValueError(\n                \"Batch record for /v1/responses is missing required `input` field: \"\n                f\"model={openai_request_body.get('model', '')}\"\n            )\n        chat_body: Final[Mapping[str, object]] = (\n            LiteLLMCompletionResponsesConfig.transform_responses_api_request_to_chat_completion_request(\n                model=openai_request_body.get(\"model\", \"\"),\n                input=_responses_input_adapter().validate_python(responses_input),\n                responses_api_request=_responses_request_adapter().validate_python(\n                    _frozen_mapping(\n                        (key, value) for key, value in openai_request_body.items() if key not in (\"model\", \"input\")\n                    )\n                ),\n                metadata=openai_request_body.get(\"metadata\"),\n            )\n        )\n        return _frozen_mapping((key, value) for key, value in chat_body.items() if key != \"tools\" or value)\n\n    @staticmethod","sourceCodeStart":717,"sourceCodeEnd":753,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/bedrock/files/transformation.py#L717-L753","documentation":"A batch record whose url is \"/v1/responses\" must carry a non-null `input`; LiteLLM runs it through the same Responses-to-Chat bridge the real-time path uses (LiteLLMCompletionResponsesConfig) before shaping the Bedrock modelInput. Without `input` there is nothing to translate, so validation fails before upload. Note that the body-shape fallback never classifies a record as RESPONSES — this error only fires on an explicit \"/v1/responses\" url.","triggerScenarios":"{\"url\": \"/v1/responses\", \"body\": {\"model\": \"...\"}} with `input` missing or null. Also when a url-less embedding-style record gets its url corrected to /v1/responses but the `input` key was dropped in the same edit.","commonSituations":"Migrating OpenAI Responses API batch files to Bedrock; generating JSONL with a template that omits `input` for some rows; serializers emitting null for absent fields.","solutions":["Add an `input` field (string or structured Responses input) to the record body","If the record is embedding-shaped, use \"/v1/embeddings\" as the url instead","Omit null keys rather than writing \"input\": null in the JSONL","Lint the file locally before upload (see snippet)"],"exampleFix":"// before (JSONL line)\n{\"custom_id\": \"req_1\", \"url\": \"/v1/responses\", \"body\": {\"model\": \"anthropic.claude-3-5-sonnet-20240620-v1:0\", \"instructions\": \"be brief\"}}\n\n// after\n{\"custom_id\": \"req_1\", \"url\": \"/v1/responses\", \"body\": {\"model\": \"anthropic.claude-3-5-sonnet-20240620-v1:0\", \"instructions\": \"be brief\", \"input\": \"Summarize this document\"}}","handlingStrategy":"validation","validationCode":"import json\n\ndef validate_responses_records(path: str) -> None:\n    for i, line in enumerate(open(path)):\n        if not line.strip():\n            continue\n        rec = json.loads(line)\n        if rec.get(\"url\") == \"/v1/responses\" and rec.get(\"body\", {}).get(\"input\") is None:\n            raise ValueError(f\"line {i}: /v1/responses record missing `input`\")","typeGuard":"def is_valid_responses_record(rec: dict) -> bool:\n    return rec.get(\"url\") != \"/v1/responses\" or rec.get(\"body\", {}).get(\"input\") is not None","tryCatchPattern":"try:\n    await client.files.create(file=batch_file, purpose=\"batch\")\nexcept ValueError as e:\n    if \"missing required `input` field\" in str(e):\n        backfill_responses_inputs()  # re-emit records with their input\n    else:\n        raise","preventionTips":["Treat url as the routing contract: /v1/responses records must carry input","Validate with a JSON schema (required: [input]) before upload","Exclude null fields when serializing batch payloads"],"tags":["bedrock","batch","responses-api","jsonl","missing-field","litellm"],"backgroundTag":"missing-required-argument","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}