Gần như mọi INVALID_ARGUMENT dạng này đều xuất phát từ việc gửi thông báo kiểu OpenAI đến endpoint generateContent gốc của Google. Endpoint này có tên role khác, nơi riêng cho chỉ dẫn hệ thống và không chấp nhận một lượt trống.
Lỗi
{"error":{"code":400,
"message":"Please use a valid role: user, model.",
"status":"INVALID_ARGUMENT"}}
{"error":{"code":400,
"message":"* GenerateContentRequest.contents: contents is not specified\n",
"status":"INVALID_ARGUMENT"}}Tổng quan nguyên nhân và cách khắc phục
| Nguyên nhân | Cách khắc phục |
|---|---|
| Thông báo kiểu OpenAI được gửi đến endpoint gốc | assistant → model, còn system chuyển sang systemInstruction. Không có gì khác là hợp lệ. |
| Mảng contents trống | Mọi thông báo đều bị lọc — thường là một lượt công cụ có content: null. |
| Một lượt có mảng parts trống | Thay vì phát ra một lượt không có part, hãy thay bằng một part văn bản trống. |
| Dữ liệu hình ảnh nội tuyến không có mimeType | inline_data cần cả mime_type và dữ liệu base64. |
Xác định bạn thực sự đang dùng API nào
Cùng một tên SDK có thể đại diện cho hai schema không tương thích: generateContent gốc của Google, nhận contents với role user và model; và /v1/chat/completions tương thích OpenAI, nhận messages với system, user và assistant. Mọi lỗi trong nhóm này đều do payload được viết cho một API nhưng lại gửi đến API kia.
Ánh xạ role nếu bạn đang dùng API gốc
Các thông báo system và developer được chuyển vào trường systemInstruction riêng. assistant trở thành model. user vẫn là user. Mọi role khác không có tương đương và phải được loại bỏ hoặc gộp trước khi gửi.
def to_gemini(messages):
system, contents = [], []
for m in messages:
if m["role"] in ("system", "developer"):
system.append(m["content"])
continue
if m["role"] not in ("user", "assistant"):
continue # no Gemini equivalent
parts = [{"text": m["content"] or ""}] # never emit empty parts
contents.append({
"role": "model" if m["role"] == "assistant" else "user",
"parts": parts,
})
req = {"contents": contents}
if system:
req["systemInstruction"] = {"parts": [{"text": "\n\n".join(system)}]}
return reqKhông bao giờ phát ra một lượt không có parts
Thông báo có content là null hoặc bị lọc thành rỗng sẽ tạo ra một lượt không có part và bị từ chối. Thay bằng một part văn bản trống giúp lượt hợp lệ và duy trì thứ tự luân phiên mà mô hình mong đợi.
Xác thực trước khi gửi
Đảm bảo contents không rỗng, mọi role đều là user hoặc model và mỗi lượt có ít nhất một part. Ba dòng tại nơi gọi, thay vì nhận lỗi 400 từ mạng.
Nếu bạn gọi qua Kunavo
Gọi Gemini qua /v1/chat/completions tương thích OpenAI của Kunavo nghĩa là bạn không cần tự xây dựng mảng contents của Google: bạn gửi các thông báo kiểu OpenAI và gateway sẽ ánh xạ — system và developer được gộp vào systemInstruction, assistant được viết lại thành model, các role không có tương đương bị loại bỏ, và một part văn bản trống được thay thế thay vì phát ra lượt không có part. Vì vậy, nhóm INVALID_ARGUMENT này không phát sinh do cấu trúc thông báo. Điều gateway không thể xử lý là một đối số thực sự không hợp lệ — chẳng hạn response_format không được hỗ trợ hoặc hình ảnh nội tuyến sai định dạng — những lỗi này vẫn bị từ chối theo đúng bản chất. Mức phí theo token cho nhóm Gemini có tại hướng dẫn giá Gemini của chúng tôi.
Câu hỏi thường gặp
Các role hợp lệ của Gemini là gì?
Trên API gốc, chính xác là hai role: user và model. Không có role system — chỉ dẫn hệ thống nằm trong trường systemInstruction riêng.
Tôi có thể gửi thông báo system không?
Không thể gửi dưới dạng một lượt. Hãy chuyển nó vào systemInstruction hoặc dùng endpoint tương thích OpenAI thực hiện việc đó cho bạn.
Tại sao payload giống hệt lại hoạt động với OpenAI?
Vì schema của OpenAI định nghĩa các role system và assistant, còn schema Gemini gốc thì không. Payload hợp lệ — nhưng là hợp lệ đối với API kia.
Hướng dẫn liên quan
- Gemini API 429 RESOURCE_EXHAUSTED — hạn ngạch và giới hạn tốc độ, cách khắc phục đúng
- Khóa API Gemini không hoạt động — API_KEY_INVALID và năm nguyên nhân
Thông tin chi tiết hơn về ý nghĩa lỗi có trong tài liệu tham chiếu lỗi; bạn chỉ mất một phút để lấy khóa qua đăng ký và hướng dẫn xác thực.