가이드 목록으로
문제 해결·2026년 8월 28일·6분 분량

Gemini API 400 INVALID_ARGUMENT — “유효한 role을 사용하세요” 및 빈 contents 계열 오류

이 형태의 INVALID_ARGUMENT는 거의 모두 OpenAI 스타일 메시지를 Google의 네이티브 generateContent 엔드포인트로 전송해서 발생합니다. role 이름이 다르고 시스템 지침을 저장하는 위치가 별도이며 빈 턴을 허용하지 않습니다.

마지막 검토일: .

이 형태의 INVALID_ARGUMENT는 거의 모두 OpenAI 스타일 메시지를 Google의 네이티브 generateContent 엔드포인트로 전송해서 발생합니다. role 이름이 다르고 시스템 지침을 저장하는 위치가 별도이며 빈 턴을 허용하지 않습니다.

오류

two members of the same family (HTTP 400)
{"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"}}

원인과 해결 방법 한눈에 보기

원인해결 방법
네이티브 엔드포인트로 전송된 OpenAI 형태의 메시지assistant → model로 바꾸고 system은 systemInstruction으로 옮깁니다. 그 외에는 어떤 것도 유효하지 않습니다.
비어 있는 contents 배열모든 메시지가 필터링됨 — content: null인 도구 턴에서 자주 발생합니다.
비어 있는 parts 배열을 가진 턴parts가 없는 턴을 전송하는 대신 빈 텍스트 part로 대체하세요.
mimeType이 없는 인라인 이미지 데이터inline_data에는 mime_type과 base64 데이터가 모두 필요합니다.

실제로 어떤 API를 사용 중인지 확인하세요

같은 SDK 이름이 서로 호환되지 않는 두 스키마를 가리킵니다. Google의 네이티브 generateContent는 user 및 model role을 포함한 contents를 받고, OpenAI 호환 /v1/chat/completions는 system, user 및 assistant를 포함한 messages를 받습니다. 이 계열의 모든 오류는 한 API용으로 작성한 페이로드를 다른 API로 전송해서 발생합니다.

네이티브 API를 사용 중이라면 role을 매핑하세요

system 및 developer 메시지는 별도의 systemInstruction 필드로 합쳐집니다. assistant는 model이 됩니다. user는 그대로 user입니다. 다른 role에는 대응되는 값이 없으므로 전송 전에 삭제하거나 병합해야 합니다.

to_gemini.py
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 req

parts가 없는 턴은 절대 전송하지 마세요

content가 null이거나 필터링되어 아무것도 남지 않은 메시지는 parts가 없는 턴을 생성하며 거부됩니다. 빈 텍스트 part로 대체하면 턴이 유효하게 유지되고 모델이 기대하는 교대 순서도 보존됩니다.

전송 전에 검증하세요

contents가 비어 있지 않고, 모든 role이 user 또는 model이며, 모든 턴에 최소 하나의 part가 있는지 단언하세요. 네트워크에서 400을 받은 뒤 처리하는 대신 호출 지점에서 세 줄로 확인할 수 있습니다.

Kunavo를 통해 호출하는 경우

Kunavo의 OpenAI 호환 /v1/chat/completions를 통해 Gemini를 호출하면 Google의 contents 배열을 직접 구성할 필요가 없습니다. OpenAI 형태의 messages를 보내면 게이트웨이가 매핑합니다. system 및 developer 메시지는 systemInstruction으로 합쳐지고, assistant는 model로 바뀌며, 대응되는 role이 없는 것은 삭제되고, parts가 없는 턴을 만드는 대신 빈 텍스트 part가 삽입됩니다. 따라서 메시지 형태 때문에 발생하는 이 계열의 INVALID_ARGUMENT는 생기지 않습니다. 다만 유효하지 않은 인수 자체까지 해결해 주는 것은 아닙니다. 지원되지 않는 response_format이나 잘못된 인라인 이미지 등은 여전히 그 자체로 거부됩니다. Gemini 제품군의 토큰당 요금은 Gemini 요금 안내.

자주 묻는 질문

Gemini에서 유효한 role은 무엇인가요?

네이티브 API에서는 정확히 두 가지입니다. user와 model입니다. system role은 없으며 시스템 지침은 별도의 systemInstruction 필드에 넣습니다.

system 메시지를 보낼 수 있나요?

턴으로는 보낼 수 없습니다. systemInstruction으로 옮기거나, 이를 대신 처리해 주는 OpenAI 호환 엔드포인트를 사용하세요.

동일한 페이로드가 OpenAI에서는 왜 작동하나요?

OpenAI의 스키마는 system 및 assistant role을 정의하지만 Gemini의 네이티브 스키마에는 없기 때문입니다. 해당 페이로드는 유효하지만 다른 API에 대해서만 유효합니다.

관련 가이드

오류 의미에 대한 자세한 내용은 오류 참조에서 확인할 수 있습니다. 가입 및 인증 가이드를 통해 1분이면 키를 받을 수 있습니다.