{"record":{"id":"0f9425475027eda4","repo":"BerriAI/litellm","slug":"batch-record-for-v1-completions-is-missing-requir","errorCode":null,"errorMessage":"Batch record for /v1/completions is missing required `prompt` field: model={openai_request_body.get('model', '')}","messagePattern":"Batch record for /v1/completions is missing required `prompt` field: model=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/bedrock/files/transformation.py","lineNumber":706,"sourceCode":"            non_default_params=non_default_params,\n            optional_params={},\n        )\n        return dict(titan_config._transform_request(input=input_text, inference_params=inference_params))\n\n    @staticmethod\n    def _transform_text_completion_body_to_chat_body(\n        openai_request_body: _OpenAIBatchRecordBody,\n    ) -> Mapping[str, object]:\n        \"\"\"\n        Rewrite an OpenAI `/v1/completions` batch body as a Chat Completions body.\n\n        Bedrock batch `modelInput` is the model's InvokeModel/Converse body, and\n        no Bedrock batch model takes a bare `prompt`, so the wrapping that\n        `litellm.text_completion` does in real time has to happen here too.\n        \"\"\"\n        prompt: Final = openai_request_body.get(\"prompt\")\n        if prompt is None:\n            raise ValueError(\n                \"Batch record for /v1/completions is missing required `prompt` field: \"\n                f\"model={openai_request_body.get('model', '')}\"\n            )\n        return _frozen_mapping(\n            chain(\n                ((key, value) for key, value in openai_request_body.items() if key != \"prompt\"),\n                ((\"messages\", text_completion_prompt_to_messages(prompt)),),\n            )\n        )\n\n    @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","sourceCodeStart":688,"sourceCodeEnd":724,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/bedrock/files/transformation.py#L688-L724","documentation":"A batch record classified as /v1/completions (url \"/v1/completions\", or a url-less body whose only shape key is `prompt`) must carry a non-null `prompt`, because LiteLLM wraps it into chat `messages` via text_completion_prompt_to_messages before building the Bedrock modelInput. No Bedrock batch model takes a bare prompt, so a missing prompt cannot be passed through. The check fails before upload, naming the record's model.","triggerScenarios":"{\"url\": \"/v1/completions\", \"body\": {\"model\": \"...\"}} with no `prompt` key, or with \"prompt\": null; also a chat-shaped record mislabeled with the /v1/completions url — the url wins classification, so the body's `messages` are ignored and `prompt` is missing.","commonSituations":"Copy-pasting a /v1/chat/completions record and only editing the url field; JSONL serializers that emit null for unset optional fields; hand-writing batch files from memory and forgetting `prompt`.","solutions":["Add a `prompt` string to the record body: \"prompt\": \"...\"","If the record is actually chat-shaped, set url to \"/v1/chat/completions\" (or drop the url so `messages` routing applies)","Configure your JSON serializer to omit null fields instead of writing \"prompt\": null","Validate each line locally before upload (see snippet)"],"exampleFix":"// before (JSONL line)\n{\"custom_id\": \"req_1\", \"url\": \"/v1/completions\", \"body\": {\"model\": \"meta.llama3-8b-instruct:0\", \"max_tokens\": 100}}\n\n// after\n{\"custom_id\": \"req_1\", \"url\": \"/v1/completions\", \"body\": {\"model\": \"meta.llama3-8b-instruct:0\", \"prompt\": \"Once upon a time\", \"max_tokens\": 100}}","handlingStrategy":"validation","validationCode":"import json\n\ndef validate_completion_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/completions\" and rec.get(\"body\", {}).get(\"prompt\") is None:\n            raise ValueError(f\"line {i}: /v1/completions record missing `prompt`\")","typeGuard":"def is_valid_completions_record(rec: dict) -> bool:\n    return rec.get(\"url\") != \"/v1/completions\" or isinstance(rec.get(\"body\", {}).get(\"prompt\"), (str, list))","tryCatchPattern":"try:\n    await client.files.create(file=batch_file, purpose=\"batch\")\nexcept ValueError as e:\n    if \"missing required `prompt` field\" in str(e):\n        repair_completions_records()  # add prompt or fix the url field\n    else:\n        raise","preventionTips":["Generate JSONL from typed request objects so required fields cannot be omitted","Serialize with nulls omitted (e.g. Pydantic exclude_none=True)","Set the url field to match the actual body shape; never hand-edit only the url"],"tags":["bedrock","batch","text-completion","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"}