{"record":{"id":"62bc109b2ed06ef6","repo":"BerriAI/litellm","slug":"400-62bc10","errorCode":"400","errorMessage":"Expected 1 model, got {len(target_model_names)}","messagePattern":"Expected 1 model, got (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/batches_endpoints/endpoints.py","lineNumber":282,"sourceCode":"                )\n\n            response.input_file_id = input_file_id\n\n        elif litellm.enable_loadbalancing_on_batch_endpoints is True and is_router_model and router_model is not None:\n            if llm_router is None:\n                raise HTTPException(\n                    status_code=500,\n                    detail={\"error\": \"LLM Router not initialized. Ensure models added to proxy.\"},\n                )\n\n            response = await llm_router.acreate_batch(**_create_batch_data)\n        elif (\n            unified_file_id and input_file_id\n        ):  # litellm_proxy:application/octet-stream;unified_id,c4843482-b176-4901-8292-7523fd0f2c6e;target_model_names,gpt-4o-mini\n            target_model_names: Final = get_models_from_unified_file_id(unified_file_id)\n            ## EXPECTS 1 MODEL\n            if len(target_model_names) != 1:\n                raise HTTPException(\n                    status_code=400,\n                    detail={\"error\": f\"Expected 1 model, got {len(target_model_names)}\"},\n                )\n            model: Final = target_model_names[0]\n            _create_batch_data[\"model\"] = model\n\n            resolved_storage_url: Final = await _resolve_managed_input_file_storage_url(input_file_id)\n            if resolved_storage_url is not None:\n                _create_batch_data[\"input_file_id\"] = resolved_storage_url\n\n            if llm_router is None:\n                raise HTTPException(\n                    status_code=500,\n                    detail={\"error\": \"LLM Router not initialized. Ensure models added to proxy.\"},\n                )\n\n            _create_batch_data.update(disable_fallbacks=True)  # pyright: ignore[reportCallIssue]  # router flag\n            response = await llm_router.acreate_batch(**_create_batch_data)","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/batches_endpoints/endpoints.py#L264-L300","documentation":"LiteLLM 'unified' file ids embed routing metadata (base64 of litellm_proxy:<purpose>;unified_id,...;target_model_names,<comma-separated models>). When POST /v1/batches receives such an id as input_file_id, the proxy parses target_model_names and must pick exactly one model to create the batch against; with a different count it returns HTTP 400 'Expected 1 model, got N'.","triggerScenarios":"POST /v1/batches where input_file_id is a unified file id whose target_model_names lists 2+ models (file uploaded for multiple models) or encodes an empty model list.","commonSituations":"Reusing a multi-model upload (meant for unified file retrieval across providers) as batch input; copying file ids from fan-out workflow logs; hand-built batch payloads referencing shared files.","solutions":["Re-upload the input file scoped to exactly one target model and use that unified file id in the batch request.","Create per-model file copies and one batch per model when several providers must run the same input.","For load-balanced batching, send a router model name in the batch body with enable_loadbalancing_on_batch_endpoints instead of a multi-model file id."],"exampleFix":"# before - file uploaded for two models, then used for a batch\ncurl -X POST \"$PROXY/v1/files\" -H \"Authorization: Bearer $KEY\" \\\n  -F purpose=batch -F file=@input.jsonl -F 'target_model_names=gpt-4o-mini,gemini-2.0-flash'\ncurl -X POST \"$PROXY/v1/batches\" -H \"Authorization: Bearer $KEY\" \\\n  -d '{\"input_file_id\": \"<multi-model-unified-file-id>\"}'\n# after - one target model per file\ncurl -X POST \"$PROXY/v1/files\" -H \"Authorization: Bearer $KEY\" \\\n  -F purpose=batch -F file=@input.jsonl -F 'target_model_names=gpt-4o-mini'\ncurl -X POST \"$PROXY/v1/batches\" -H \"Authorization: Bearer $KEY\" \\\n  -d '{\"input_file_id\": \"<single-model-file-id>\"}'","handlingStrategy":"validation","validationCode":"import base64\n\ndef count_target_models(unified_file_id: str) -> int:\n    try:\n        raw = base64.b64decode(unified_file_id + '==').decode('utf-8', errors='ignore')\n    except Exception:\n        return 0\n    for part in raw.split(';'):\n        if part.startswith('target_model_names,'):\n            return len([m for m in part.split(',', 1)[1].split(',') if m.strip()])\n    return 0\n\n# run before creating a batch\nassert count_target_models(input_file_id) == 1, 'use a single-model unified file id'","typeGuard":"import base64\n\ndef is_single_model_file_id(file_id: str) -> bool:\n    try:\n        raw = base64.b64decode(file_id + '==').decode('utf-8', errors='ignore')\n    except Exception:\n        return False\n    for part in raw.split(';'):\n        if part.startswith('target_model_names,'):\n            names = [m for m in part.split(',', 1)[1].split(',') if m.strip()]\n            return len(names) == 1\n    return False","tryCatchPattern":"try:\n    batch = await client.batches.create(input_file_id=fid, ...)\nexcept openai.BadRequestError as e:\n    if 'Expected 1 model' in str(e):\n        fid = await reupload_scoped_to_single_model()  # re-upload with one target model\n        batch = await client.batches.create(input_file_id=fid, ...)\n    else:\n        raise","preventionTips":["Upload batch input files scoped to exactly one target_model_names value.","Never reuse multi-model unified file ids (fan-out retrieval) as batch inputs.","Assert the decoded id contains a single model before submitting the batch."],"tags":["litellm-proxy","batches","files","unified-file-id","request-validation","http-400"],"backgroundTag":"invalid-request-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}