|

Gemini 이미지 모델 ‘required oneof field data’ 오류 해결을 위한 6가지 일반적인 원인과 수정 방법

작성자 주: gemini-3.1-flash-image-preview 등 Gemini 이미지 모델 호출 시 발생하는 required oneof field data must have one initialized field 400 오류의 6가지 일반적인 원인과 해결 방법 상세 설명

gemini-image-api-required-oneof-field-data-error-fix-ko 图示

gemini-3.1-flash-image-preview(Nano Banana 2)나 gemini-3.0-pro-image(Nano Banana Pro)로 이미지를 생성할 때, 많은 개발자들이 이 혼란스러운 400 오류를 만나게 됩니다:

{
  "status_code": 400,
  "error": {
    "message": "* GenerateContentRequest.contents[0].parts[2].data: required oneof field 'data' must have one initialized field",
    "type": "upstream_error",
    "code": 400
  }
}

이 오류 메시지의 핵심 의미는: 당신이 보낸 요청 본문에서, 특정 parts 요소의 data 필드가 비어 있거나 형식이 올바르지 않습니다. 400 오류는 클라이언트 요청 파라미터 오류에 해당하며, 자동으로 복구되지 않으므로 반드시 코드를 수정해야 합니다.

이 글에서는 이 오류를 일으키는 6가지 일반적인 원인을 정리했습니다. 각 원인마다 잘못된 코드와 올바른 코드를 비교하여 제시하므로, 여러분이 빠르게 문제를 찾아 수정할 수 있도록 도와드립니다.

핵심 가치: 이 글을 읽고 나면, 오류 메시지에 있는 parts[N] 인덱스 번호를 통해 문제 위치를 정확히 찾아내고, 6가지 원인을 하나씩 확인해보며 보통 5분 안에 문제를 해결할 수 있습니다.


Gemini 이미지 모델 오류 required oneof field data 핵심 분석

요점 설명 조사 방향
오류 본질 parts 배열에 비어 있거나 형식이 잘못된 요소가 존재함 contents[].parts[]의 각 요소 확인
핵심 단서 parts[2]는 세 번째 요소를 의미함(0부터 시작) 해당 인덱스의 part를 직접 확인
오류 유형 400 INVALID_ARGUMENT, 클라이언트 오류 자동 복구되지 않음, 코드 수정 필수
영향 범위 모든 Gemini 이미지 모델에 공통 적용 NB2, NB Pro, Gemini Flash 모두 해당
수정 난이도 낮음, 일반적으로 형식 문제 올바른 형식과 비교하여 수정

Gemini 이미지 모델 오류 메시지 구조 해석

먼저 오류 메시지의 구조를 분석해보면, 이는 문제를 찾는 핵심입니다:

GenerateContentRequest.contents[0].parts[2].data
                       ^^^^^^^^     ^^^^^^^^
                       │            │
                       │            └── 세 번째 part(인덱스는 0부터 시작)
                       └── 첫 번째 content 블록
  • contents[0]: 요청 본문의 첫 번째 content 객체를 가리킴
  • parts[2]: 해당 content의 세 번째 part 요소를 가리킴
  • data: 해당 part의 데이터 필드가 비어 있거나 올바르게 초기화되지 않음

조사 접근법: 코드에서 contents 배열의 [0]번째 요소의 parts 배열 [2]번째 요소를 직접 확인하고, 실제로 무엇을 전달했는지 살펴보세요.

gemini-image-api-required-oneof-field-data-error-fix-ko 图示


원인 1: parts에 빈 객체 또는 빈 문자열이 포함됨

가장 흔한 원인입니다. 요청의 parts 배열에 {}, null, 빈 문자열 ""와 같은 빈 값 요소가 섞여 있습니다.

잘못된 예시 올바른 예시
parts{} 빈 객체 포함 각 part에는 반드시 text 또는 inlineData가 있어야 함
parts{"text": ""} 포함 빈 텍스트도 오류를 유발하므로, 최소 한 글자 이상 작성
partsnull 요소 포함 모든 null 값 제거

잘못된 코드:

# ❌ parts에 빈 객체가 있음
payload = {
    "contents": [{
        "parts": [
            {"text": "고양이 이미지 생성해줘"},
            {},                              # ← 빈 객체, 오류 발생
            {"text": "수채화 스타일로"}
        ]
    }]
}

올바른 코드:

# ✅ 각 part에 유효한 내용이 있음
payload = {
    "contents": [{
        "parts": [
            {"text": "수채화 스타일의 고양이 이미지를 생성해줘"}
        ]
    }]
}

수정 포인트: 텍스트를 하나의 text part로 합치거나, 각 part가 유효한 text 또는 inlineData 필드를 포함하도록 보장하세요.

원인 2: 이미지 base64 데이터가 비어 있거나 형식이 잘못됨

이미지-이미지 변환 요청을 보낼 때, inlineData의 base64 데이터가 비어 있거나, 손상되었거나, 형식이 올바르지 않을 수 있습니다.

잘못된 코드:

# ❌ base64 데이터에 data URI 접두사가 포함됨
payload = {
    "contents": [{
        "parts": [
            {
                "inlineData": {
                    "mimeType": "image/png",
                    "data": "data:image/png;base64,iVBORw0KGgo..."  # ← 접두사 포함하면 안 됨
                }
            },
            {"text": "배경을 파란색으로 바꿔줘"}
        ]
    }]
}
# ❌ base64 데이터가 빈 문자열
"inlineData": {
    "mimeType": "image/jpeg",
    "data": ""          # ← 빈 데이터, 바로 오류 발생
}

올바른 코드:

import base64
import pathlib

# ✅ 이미지를 올바르게 읽어서 순수 base64로 변환
image_bytes = pathlib.Path("input.png").read_bytes()
image_b64 = base64.b64encode(image_bytes).decode("utf-8")

payload = {
    "contents": [{
        "parts": [
            {
                "inlineData": {
                    "mimeType": "image/png",
                    "data": image_b64       # ← 순수 base64 문자열, 접두사 없음
                }
            },
            {"text": "배경을 파란색으로 바꿔줘"}
        ]
    }]
}

수정 포인트:

  • data 필드는 순수 base64 문자열만 받습니다. data:image/png;base64, 같은 접두사를 포함하면 안 됩니다.
  • 이미지 파일이 실제로 존재하고 성공적으로 읽혔는지 확인하여 빈 문자열이 전달되지 않도록 하세요.
  • mimeType은 실제 이미지 형식과 일치해야 합니다(image/png, image/jpeg, image/webp).

원인 3: File 객체가 내용 참조로 올바르게 변환되지 않음

Google GenAI SDK의 Files API로 파일을 업로드한 후, File 객체를 contents에 직접 전달하면 SDK가 올바르게 변환하지 못할 수 있습니다.

잘못된 코드:

from google import genai

client = genai.Client(api_key="YOUR_KEY")

# 파일 업로드
file = client.files.upload(file="photo.png")

# ❌ 일부 SDK 버전에서는 File 객체를 직접 전달하면 실패할 수 있음
response = client.models.generate_content(
    model="gemini-3.1-flash-image-preview",
    contents=["이 이미지를 편집해줘", file]    # ← File 객체가 자동 변환되지 않을 수 있음
)

올바른 코드:

from google import genai
from google.genai import types

client = genai.Client(api_key="YOUR_KEY")

# 파일 업로드
file = client.files.upload(file="photo.png")

# ✅ 방법 1: 파일 참조를 수동으로 구성
response = client.models.generate_content(
    model="gemini-3.1-flash-image-preview",
    contents=[
        types.Content(parts=[
            types.Part(file_data=types.FileData(file_uri=file.uri, mime_type=file.mime_type)),
            types.Part(text="이 이미지를 편집해줘: 배경을 석양으로 바꿔줘")
        ])
    ],
    config=types.GenerateContentConfig(
        response_modalities=["TEXT", "IMAGE"]
    )
)
# ✅ 방법 2: inlineData와 base64를 사용하여 직접 전달 (더 안정적)
import base64, pathlib

image_b64 = base64.b64encode(pathlib.Path("photo.png").read_bytes()).decode()

response = client.models.generate_content(
    model="gemini-3.1-flash-image-preview",
    contents=[
        types.Content(parts=[
            types.Part(inline_data=types.Blob(mime_type="image/png", data=image_b64)),
            types.Part(text="이 이미지를 편집해줘: 배경을 석양으로 바꿔줘")
        ])
    ],
    config=types.GenerateContentConfig(
        response_modalities=["TEXT", "IMAGE"]
    )
)

수정 포인트: inlineData + base64 방식을 사용하여 이미지 데이터를 직접 전달하는 것이 Files API보다 더 안정적이고 권장됩니다.

원인 4: 다중 턴 대화 기록에 빈 내용이 포함됨

다중 턴 대화로 이미지를 편집할 때, 이전 턴의 응답이 올바르게 처리되지 않으면 대화 기록에 빈 content 블록이 섞일 수 있습니다.

잘못된 코드:

# ❌ 대화 기록에 빈 parts가 섞여 있음
history = [
    {"role": "user", "parts": [{"text": "로고를 생성해줘"}]},
    {"role": "model", "parts": []},        # ← 빈 parts, 오류 발생
    {"role": "user", "parts": [{"text": "파란색으로 만들어줘"}]}
]

payload = {"contents": history}

올바른 코드:

# ✅ 빈 content 블록을 필터링
history = [
    {"role": "user", "parts": [{"text": "로고를 생성해줘"}]},
    {"role": "model", "parts": [{"text": "제가 생성한 로고입니다."}]},
    {"role": "user", "parts": [{"text": "파란색으로 만들어줘"}]}
]

# 안전한 필터링: parts가 빈 목록인 레코드 제거
clean_history = [msg for msg in history if msg.get("parts") and len(msg["parts"]) > 0]

payload = {"contents": clean_history}

수정 포인트: 요청을 보내기 전에 contents 배열을 순회하며 parts가 빈 목록이거나 빈 객체를 포함하는 모든 요소를 필터링하세요.

원인 5: REST API 요청에서 JSON 필드명 대소문자 오류

Gemini API의 JSON 필드명은 camelCase(카멜 케이스)를 사용하며 대소문자를 구분합니다. 필드명을 잘못 입력하면 해당 필드가 무시되어 빈 데이터를 전송한 것과 같게 됩니다.

잘못된 필드명 올바른 필드명 설명
inline_data inlineData REST API는 camelCase 사용
mime_type mimeType REST API는 camelCase 사용
file_uri fileUri REST API는 camelCase 사용
response_modalities responseModalities REST API는 camelCase 사용
image_config imageConfig REST API는 camelCase 사용
aspect_ratio aspectRatio REST API는 camelCase 사용
image_size imageSize REST API는 camelCase 사용

잘못된 코드:

# ❌ REST API에서 snake_case(Python SDK 스타일) 사용
payload = {
    "contents": [{
        "parts": [{
            "inline_data": {           # ← inlineData여야 함
                "mime_type": "image/png",   # ← mimeType이어야 함
                "data": image_b64
            }
        }]
    }],
    "generation_config": {             # ← generationConfig여야 함
        "response_modalities": ["IMAGE"]   # ← responseModalities여야 함
    }
}

올바른 코드:

# ✅ REST API는 camelCase 사용
payload = {
    "contents": [{
        "parts": [{
            "inlineData": {
                "mimeType": "image/png",
                "data": image_b64
            }
        }]
    }],
    "generationConfig": {
        "responseModalities": ["IMAGE"],
        "imageConfig": {
            "aspectRatio": "1:1",
            "imageSize": "2K"
        }
    }
}

🎯 혼동 주의: Python SDK(google-genai)는 snake_case(예: inline_data)를 사용하지만, REST API를 직접 호출할 때는 camelCase(예: inlineData)를 사용합니다. APIYI apiyi.com 같은 API 중계 서비스 플랫폼을 통해 호출할 때는 REST API 형식을 사용하므로 반드시 camelCase를 사용해야 합니다.

원인 6: 이미지 형식이 지원되지 않거나 파일이 손상됨

전달한 이미지에 base64 데이터는 있지만, 이미지 자체의 형식이 지원되지 않거나 파일이 손상된 경우입니다.

Gemini 이미지 모델이 지원하는 입력 형식:

형식 mimeType 지원 상태
PNG image/png 지원
JPEG image/jpeg 지원
WebP image/webp 지원
GIF image/gif 부분 지원(첫 번째 프레임만)
BMP image/bmp 지원 안 함
SVG image/svg+xml 지원 안 함
TIFF image/tiff 지원 안 함

문제 해결 방법:

import base64

# base64 데이터가 유효한지 확인
def validate_image_data(b64_string, mime_type):
    # 1. 비어 있는지 확인
    if not b64_string:
        print("ERROR: base64 데이터가 비어 있습니다.")
        return False

    # 2. data URI 접두사가 포함되었는지 확인
    if b64_string.startswith("data:"):
        print("ERROR: 'data:image/...;base64,' 접두사를 제거하세요.")
        return False

    # 3. base64가 디코딩 가능한지 확인
    try:
        decoded = base64.b64decode(b64_string)
        print(f"OK: 디코딩된 크기 = {len(decoded)} 바이트")
    except Exception as e:
        print(f"ERROR: 유효하지 않은 base64 - {e}")
        return False

    # 4. mimeType이 지원되는지 확인
    supported = ["image/png", "image/jpeg", "image/webp", "image/gif"]
    if mime_type not in supported:
        print(f"ERROR: 지원되지 않는 mimeType '{mime_type}'")
        return False

    print("PASS: 이미지 데이터가 유효합니다.")
    return True

💡 권장사항: 요청을 보내기 전에 데이터 검증 함수를 추가하면 대부분의 형식 문제를 미리 발견할 수 있습니다. APIYI apiyi.com 플랫폼을 통해 호출할 때도 동일하게 적용됩니다.


Gemini 이미지 모델 오류 완전 점검 목록

required oneof field 'data' 오류가 발생하면 아래 목록을 따라 하나씩 점검해 보세요.

gemini-image-api-required-oneof-field-data-error-fix-ko 图示

점검 단계 확인 내용 해결 방법
Step 1 parts[N]에서 N이 몇 번째 요소인지 확인 코드에서 해당 위치를 직접 찾아보세요
Step 2 해당 part가 {}, null, ""인지 확인 빈 요소를 제거하거나 유효한 내용으로 채우세요
Step 3 inlineData라면 base64가 비어 있는지 확인 이미지 파일이 성공적으로 읽혔는지 확인하세요
Step 4 base64에 data: 접두사가 포함되었는지 확인 접두사를 제거하고 순수 base64만 남기세요
Step 5 JSON 필드명이 camelCase로 되어 있는지 확인 REST API는 inlineData를 사용해야 하며 inline_data가 아닙니다
Step 6 이미지 형식이 지원되는지 확인 PNG/JPEG/WebP/GIF만 지원됩니다

빠른 수정: 개발 단계에서 이 오류를 자주 접한다면, 요청을 보내기 전에 validate_payload() 함수를 추가하여 parts 배열의 각 요소가 유효한지 자동으로 검사하는 것을 권장합니다. APIYI apiyi.com 플랫폼을 통해 Gemini 이미지 모델을 호출할 때도 요청 형식은 공식 REST API와 완전히 동일하므로, 위의 점검 방법이 그대로 적용됩니다.

Gemini 이미지 모델 오류 해결 및 올바른 요청 형식 참고

순수 텍스트-이미지 변환 (Text-to-Image) 올바른 형식

import requests, base64

API_KEY = "your-apiyi-api-key"
ENDPOINT = "https://api.apiyi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent"

# ✅ 가장 간단한 올바른 형식
payload = {
    "contents": [{
        "parts": [
            {"text": "창턱에 앉아 있는 귀여운 주황색 고양이, 수채화 스타일, 4K"}
        ]
    }],
    "generationConfig": {
        "responseModalities": ["IMAGE"],
        "imageConfig": {
            "aspectRatio": "1:1",
            "imageSize": "2K"
        }
    }
}

response = requests.post(
    ENDPOINT,
    headers={"Content-Type": "application/json", "x-goog-api-key": API_KEY},
    json=payload,
    timeout=120
)

result = response.json()
image_data = result["candidates"][0]["content"]["parts"][0]["inlineData"]["data"]
with open("output.png", "wb") as f:
    f.write(base64.b64decode(image_data))

이미지-이미지 변환 (Image-to-Image) 올바른 형식

이미지-이미지 변환 전체 올바른 코드 보기
import requests
import base64
import pathlib

API_KEY = "your-apiyi-api-key"
ENDPOINT = "https://api.apiyi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent"

# 원본 이미지 읽어서 순수 base64로 변환
image_path = pathlib.Path("input_photo.png")
if not image_path.exists():
    raise FileNotFoundError(f"Image not found: {image_path}")

image_bytes = image_path.read_bytes()
image_b64 = base64.b64encode(image_bytes).decode("utf-8")

# 데이터 검증
assert len(image_b64) > 0, "Base64 데이터가 비어 있습니다"
assert not image_b64.startswith("data:"), "data URI 접두사를 제거하세요"

# ✅ 올바른 이미지-이미지 변환 요청 형식
payload = {
    "contents": [{
        "parts": [
            {
                "inlineData": {
                    "mimeType": "image/png",
                    "data": image_b64
                }
            },
            {
                "text": "배경을 석양이 지는 해변 풍경으로 바꾸고, 주체는 그대로 유지하세요"
            }
        ]
    }],
    "generationConfig": {
        "responseModalities": ["IMAGE"],
        "imageConfig": {
            "aspectRatio": "1:1",
            "imageSize": "2K"
        }
    }
}

response = requests.post(
    ENDPOINT,
    headers={"Content-Type": "application/json", "x-goog-api-key": API_KEY},
    json=payload,
    timeout=120
)

if response.status_code == 200:
    result = response.json()
    output_data = result["candidates"][0]["content"]["parts"][0]["inlineData"]["data"]
    with open("output_edited.png", "wb") as f:
        f.write(base64.b64decode(output_data))
    print("성공! 이미지가 저장되었습니다.")
else:
    print(f"오류 {response.status_code}: {response.text}")

권장사항: 텍스트-이미지 변환 시나리오에서는 가장 간단한 형식부터 시작해서 정상 작동을 확인한 후, 점진적으로 매개변수를 추가하는 것이 좋습니다. APIYI apiyi.com 플랫폼을 통해 Nano Banana 2를 호출하면, 요청당 $0.045로 청구되므로 디버깅 단계의 비용이 매우 낮습니다.


자주 묻는 질문

Q1: 오류 메시지에서 parts[2]는 무슨 뜻인가요?

parts[2]parts 배열에서 인덱스가 2인 요소, 즉 세 번째 요소를 의미합니다(인덱스는 0부터 시작). 코드에서 contents[0].parts 배열의 세 번째 요소를 직접 찾아서 내용을 확인하세요. 만약 parts 배열에 요소가 2개만 있다면(인덱스 0과 1), 코드 로직에서 parts를 연결할 때 실수로 빈 요소를 추가했을 가능성이 있습니다.

Q2: APIYI를 통해 호출할 때도 이 오류가 발생하나요?

네, 발생합니다. APIYI apiyi.com은 중계 플랫폼으로, 여러분의 요청을 Gemini 백엔드에 그대로 전달합니다. 요청 본문 자체에 형식 문제가 있다면, 백엔드에서 동일한 400 오류를 반환합니다. APIYI는 여러분의 요청 본문 구조를 수정하지 않으므로, 요청 형식이 올바른지 확인하는 것은 개발자의 책임입니다. 다행히도 수정 방법은 Google API를 직접 호출할 때와 완전히 동일합니다.

Q3: Python SDK와 REST API의 필드 이름이 왜 다르나요?

Google GenAI Python SDK는 Python의 snake_case 명명 규칙(예: inline_data, mime_type)을 따르며, SDK 내부에서 자동으로 API가 요구하는 camelCase로 변환합니다. 하지만 requests 라이브러리를 사용해 REST API를 직접 호출할 때(APIYI apiyi.com을 통해 호출하는 경우 포함)는 반드시 수동으로 camelCase 형식(예: inlineData, mimeType)을 사용해야 합니다. 그렇지 않으면 필드가 무시되어 오류가 발생할 수 있습니다.

Q4: 이 오류와 ‘contents.parts must not be empty’는 같은 오류인가요?

완전히 같지는 않지만, 원인이 유사합니다. contents.parts must not be empty는 parts 배열 자체가 비어 있는 경우("parts": [])에 발생하고, required oneof field 'data'는 parts에 요소가 존재하지만 해당 요소의 데이터 필드가 초기화되지 않은 경우(예: "parts": [{}])에 발생합니다. 해결 방법은 동일합니다: 각 part가 유효한 text 또는 inlineData를 포함하고 있는지 확인하세요.


요약

Gemini 이미지 모델 required oneof field 'data' 오류의 핵심 포인트:

  1. 근본 원인: parts 배열에 빈 객체, 빈 데이터 또는 형식이 잘못된 요소가 존재
  2. 위치 파악 방법: 오류 메시지의 parts[N] 인덱스 번호를 통해 코드의 해당 위치를 직접 확인
  3. 가장 흔한 원인: 빈 객체 {}, data: 접두사가 포함된 base64, JSON 필드명 대소문자 오류
  4. REST API는 camelCase 필수: inlineData ( inline_data 아님), mimeType ( mime_type 아님)
  5. 예방 조치: 전송 전 페이로드 검증 함수를 추가하여 빈 요소와 형식 문제를 자동으로 감지

개발 및 디버깅을 위해 APIYI apiyi.com 플랫폼을 통해 Gemini 이미지 모델을 호출하는 것을 추천합니다. Nano Banana 2는 횟수당 $0.045로 매우 낮은 디버깅 비용을 제공하며, 인터페이스 형식은 공식 REST API와 완벽하게 호환됩니다.


📚 참고 자료

  1. Gemini API 이미지 생성 공식 문서: 완전한 요청 형식 및 매개변수 설명

    • 링크: ai.google.dev/gemini-api/docs/image-generation
    • 설명: 텍스트-이미지 변환 및 이미지-이미지 변환의 표준 요청 형식 포함
  2. Gemini API 오류 해결 가이드: 공식 제공 오류 코드 및 수정 제안

    • 링크: ai.google.dev/gemini-api/docs/troubleshooting
    • 설명: 400, 429, 500 등 일반적인 오류 해결 방법 포함
  3. GitHub Issue: required oneof field data 오류 토론: 커뮤니티 보고 및 수정 방안

    • 링크: github.com/google-gemini/cookbook/issues/786
    • 설명: File 객체 전달로 인한 이 오류의 상세 분석 및 해결 방법 포함
  4. APIYI Nano Banana 2 연동 문서: APIYI 플랫폼에서 Gemini 이미지 모델 호출에 대한 완전한 가이드

    • 링크: docs.apiyi.com/en/api-capabilities/nano-banana-2-image
    • 설명: 올바른 요청 형식 예시 및 자주 묻는 질문 포함

저자: APIYI 기술 팀
기술 교류: Gemini API 호출 문제가 발생하면 APIYI docs.apiyi.com 문서 센터를 방문하여 더 많은 문제 해결 가이드를 확인하세요

Similar Posts