본문으로 건너뛰기

Nano Banana 2 Thought Signature 오류: 이미지 편집 두 번째 턴 400 해결

Nano Banana 2 이미지 편집의 두 번째 요청이 400이면 이전 이미지의 사고 서명이 빠진 것입니다. previous_interaction_id나 SDK chat으로 서명을 돌려주세요.

LaoZhang AI Team게시업데이트 8 분 소요
목차
Nano Banana 2 두 번째 이미지 편집 턴에서 응답 상태와 사고 서명을 보존하는 개념도

Nano Banana 2(gemini-3.1-flash-image)로 이미지를 만든 뒤 "색만 바꿔 줘" 같은 두 번째 요청을 보냈는데 400 INVALID_ARGUMENT와 함께 Image part is missing a thought_signature in content position 2, part position 1 같은 문구가 돌아왔다면, 원인은 하나입니다. 이전 턴에 모델이 돌려준 이미지 part를 다시 보내면서 거기에 붙어 있던 사고 서명(thought signature)을 빼 버린 것입니다. 해결도 서명을 손대지 않고 그대로 돌려주는 것뿐이며, 방법은 아래 세 가지 순서로 고르면 됩니다.

지금 쓰는 방식할 일
Interactions API (client.interactions.create)두 번째 요청에 previous_interaction_id를 넘깁니다. 서명은 서버가 보관합니다
generateContent (client.models.generate_content)SDK의 chat을 쓰거나, 이전 응답의 content를 수정 없이 기록에 추가합니다
Vercel AI SDK, Dify, n8n 같은 프레임워크이미지 서명을 지원하는 버전으로 올리고, 없으면 해당 프로젝트의 issue를 확인합니다

아래 Python 예제는 Google 문서(2026년 10월 5일 기준)의 예제 형태를 현행 모델 ID로 옮겨 정리한 것으로, 실행해 본 코드는 아닙니다. 적용 전에 사용 중인 SDK 버전에서 한 번 돌려 보세요.

'Image part is missing a thought_signature' 400이 나는 이유

Google의 Thinking 가이드는 사고 서명을 "모델 내부 추론을 암호화한 표현"이라고 설명하고, 여러 턴에 걸쳐 추론을 이어 가려면 이 값이 필요하다고 적고 있습니다. 서명은 사람이 읽는 값이 아니라, 모델이 다음 턴에서 직전 작업의 맥락을 이어받기 위한 상태 값입니다. 예전 thought-signatures 문서 주소는 2026년 10월 5일 기준 이 Thinking 가이드로 옮겨져 있습니다.

서명이 붙는 위치는 API마다 다릅니다.

  • generateContent: 별도의 사고 블록이 없고, 서명은 응답 part에 붙는 메타데이터입니다. functionCall part나 응답의 마지막 part에 붙으며, 마지막 part가 inlineData, 즉 이미지일 수도 있습니다.
  • Interactions API: 사고가 독립된 thought step으로 나오고, 서명은 thought step과 Google 검색 같은 내장 도구 step에만 붙습니다.

두 번째 턴이 깨지는 전형적인 경로는 이렇습니다. 첫 턴 응답에서 이미지 바이트만 꺼내 저장하고, 다음 요청 때 대화 기록을 {"role": "model", "parts": [이미지]}처럼 직접 다시 만듭니다. 이때 원래 part에 있던 thoughtSignature 필드가 빠집니다. 대화 기록을 "역할 + 텍스트 + 첨부 파일" 형태의 일반 메시지로 보관하는 프레임워크에서 특히 자주 생깁니다. Vercel AI SDK에서 보고된 사례(issue #12988)도 SDK가 이전 이미지를 서명 없이 다시 보내면서 위 문구의 400이 난 경우였습니다.

오류 문구의 content position과 part position은 요청 contents 배열에서 몇 번째 메시지의 몇 번째 part가 문제인지를 가리킵니다. 번호를 0부터 세는지 1부터 세는지는 문서에 나와 있지 않으니, 실패한 요청 본문을 로그로 남겨 해당 위치의 part에 thoughtSignature가 있는지 직접 대조하는 편이 빠릅니다. Google의 API 오류 목록에는 같은 상황이 missing_thought_signature(응답에 필요한 사고 서명이 없음)라는 코드로 올라 있습니다.

이 400은 재시도로 풀리지 않습니다. 같은 기록을 다시 보내면 같은 오류가 납니다.

해결 1: Interactions API에서 previous_interaction_id로 이어 가기

가장 손이 덜 가는 방법은 서명을 아예 직접 다루지 않는 것입니다. Thinking 가이드에 따르면 Interactions API의 상태 유지 모드(store: true, 그리고 다음 턴에 previous_interaction_id 전달)에서는 서버가 사고 블록과 서명을 포함한 대화 상태를 관리하므로 서명에 관해 할 일이 없습니다. Google의 이미지 생성 가이드도 멀티턴 편집 예제를 이 방식으로 씁니다.

python
import base64
from google import genai

client = genai.Client()
MODEL = "gemini-3.1-flash-image"

# 1턴: 이미지 생성
first = client.interactions.create(
    model=MODEL,
    input="흰 대리석 화장대 위에 놓인 투명한 향수병 사진을 만들어 줘",
)
with open("v1.png", "wb") as f:
    f.write(base64.b64decode(first.output_image.data))

# 2턴: 이전 interaction의 id만 넘기면 서명은 서버 쪽에서 이어집니다
second = client.interactions.create(
    model=MODEL,
    input="향수병 색만 보라색으로 바꾸고 나머지는 그대로 둬",
    previous_interaction_id=first.id,
)
if second.output_image:
    with open("v2.png", "wb") as f:
        f.write(base64.b64decode(second.output_image.data))

Google 이미지 가이드의 편집 예제도 store를 따로 지정하지 않고 previous_interaction_id만 넘깁니다. 이 방식에서는 이전 이미지를 input에 다시 넣을 필요가 없습니다. 이전 턴의 결과물은 previous_interaction_id가 가리키는 상태에 이미 들어 있습니다.

대화 상태를 서버에 두지 않고 매번 전체 기록을 보내는 무상태 방식으로 Interactions API를 쓴다면 규칙이 달라집니다. 모델에게 받은 사고 블록을 받은 그대로 전부 다시 보내야 하며, 지우거나 고치면 안 됩니다. Google 검색 같은 내장 도구의 호출·결과 step에 붙은 서명도 함께 보내야 합니다.

해결 2: generateContent는 SDK chat이나 응답 content를 그대로 추가

기존 코드가 generate_content 기반이라 Interactions API로 옮기기 어렵다면, 서명이 붙은 part를 원래 모양 그대로 다음 요청에 넣으면 됩니다. Google Cloud의 사고 서명 문서는 공식 Google Gen AI SDK의 chat 기록 기능을 쓰거나 모델 응답 전체를 기록에 추가하면 서명이 자동으로 처리된다고 설명합니다.

가장 간단한 쪽은 chat입니다.

python
from google import genai
from google.genai import types

client = genai.Client()

chat = client.chats.create(
    model="gemini-3.1-flash-image",
    config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
)

def save_image(response, path):
    for part in response.candidates[0].content.parts:
        if part.inline_data:
            with open(path, "wb") as f:
                f.write(part.inline_data.data)

r1 = chat.send_message("흰 대리석 화장대 위에 놓인 투명한 향수병 사진을 만들어 줘")
save_image(r1, "v1.png")

# chat 객체가 1턴 응답(서명 포함)을 기록에 보관하고 있습니다
r2 = chat.send_message("향수병 색만 보라색으로 바꾸고 나머지는 그대로 둬")
save_image(r2, "v2.png")

대화 기록을 직접 관리해야 한다면 응답의 content 객체를 통째로 붙이십시오. part를 하나씩 꺼내 새 dict로 다시 조립하는 순간 서명이 빠지기 쉽습니다.

python
cfg = types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"])
contents = [types.Content(role="user", parts=[types.Part(text="투명한 향수병 사진을 만들어 줘")])]

r1 = client.models.generate_content(model="gemini-3.1-flash-image", contents=contents, config=cfg)

# 올바른 방법: 서명이 붙은 part가 들어 있는 content를 수정 없이 추가
contents.append(r1.candidates[0].content)
# 400이 나는 방법: 이미지 바이트만 꺼내 model 메시지를 새로 만드는 것

contents.append(types.Content(role="user", parts=[types.Part(text="병 색만 보라색으로 바꿔 줘")]))
r2 = client.models.generate_content(model="gemini-3.1-flash-image", contents=contents, config=cfg)

REST로 직접 호출하거나 기록을 데이터베이스에 저장했다가 복원한다면, 모델 턴의 각 part를 받은 그대로 직렬화해 두어야 합니다. 이미지 part라면 대략 이런 모양이어야 합니다.

json
{
  "role": "model",
  "parts": [
    {
      "inlineData": { "mimeType": "image/png", "data": "BASE64_IMAGE" },
      "thoughtSignature": "SIGNATURE_FROM_RESPONSE"
    }
  ]
}

Google Cloud 문서가 덧붙이는 주의점도 같은 맥락입니다. 서명은 원래 들어 있던 part 안에 둔 채 돌려보내야 하고, 서명이 있는 part와 없는 part를 하나로 합치거나 서명이 있는 part 두 개를 합치면 안 됩니다. 기록을 다듬거나 줄이는 코드가 있다면 이 규칙을 지키는지 확인하십시오.

해결 3: 서명을 버리는 프레임워크는 업데이트하거나 issue 확인

직접 API를 부르지 않고 프레임워크나 워크플로 도구를 거친다면, 서명을 버리는 쪽은 대개 그 도구입니다. 사용자 코드로는 고칠 수 없으므로 도구를 업데이트하는 것이 첫 번째 대응입니다.

  • Vercel AI SDK: issue #12988(2026년 3월 2일 등록, 종료)은 Nano Banana 2로 이미지를 만든 다음 턴에서 위 400이 나는 문제였습니다. "fix missing support for image thought signatures" 수정이 ai 6.0.114에 포함됐으므로, 그보다 낮은 버전이면 올리면 됩니다.
  • Dify의 Gemini 플러그인, n8n: Gemini 3 계열 모델에서 두 번째 생성이나 도구 호출 단계가 서명 문제로 실패한다는 사용자 보고가 올라와 있습니다. 현재 버전의 수정 여부는 각 프로젝트의 issue와 릴리스 노트에서 확인해야 합니다.

업데이트로 해결되지 않으면, 해당 프로젝트에 issue가 있는지 찾아보고 없으면 오류 원문과 모델 ID, 도구 버전을 붙여 새로 올리는 것이 가장 확실합니다. 급하게 돌아가야 하는 흐름이라면 이미지 편집 단계만 위의 Interactions API나 SDK chat으로 직접 호출하는 HTTP 노드나 함수로 빼는 방법도 있습니다.

OpenAI 호환 형식(Chat Completions)으로 Gemini를 쓰는 경우, Google Cloud 문서의 함수 호출 예제는 서명을 각 tool_calls 항목의 extra_content.google.thought_signature에 담아 주고받습니다. 중간 게이트웨이나 클라이언트 라이브러리가 이 필드를 버리면 같은 400이 납니다. 이 형식에서 이미지 part 서명을 어떻게 다루는지는 문서에 예시가 없습니다.

Nano Banana Pro에서 되던 코드가 Nano Banana 2에서 깨지는 이유

같은 코드가 Nano Banana Pro(gemini-3-pro-image)에서는 돌아가는데 Nano Banana 2에서만 400이 난다면, 두 모델의 검증 강도가 다르기 때문일 가능성이 큽니다.

모델이미지 part 서명을 빼고 보냈을 때근거
Nano Banana Pro (gemini-3-pro-image)400을 내지 않음. 다만 맥락 유지를 위해 돌려보내야 함Google Cloud 사고 서명 문서
Nano Banana 2 (gemini-3.1-flash-image)400 INVALID_ARGUMENTVercel AI SDK issue #12988의 개발자 보고

Google Cloud 문서는 일반 규칙으로 "함수 호출이 아닌 part의 서명은 엄격하게 검증하지 않는다"고 적고 있지만, Nano Banana 2의 이미지 part에서는 실제로 400이 보고됐습니다. 문서의 일반 규칙만 믿고 이미지 서명을 생략하기보다, 모든 모델에서 서명을 받은 그대로 돌려주는 코드로 맞추는 편이 안전합니다. Pro에서도 그렇게 해야 편집 맥락이 유지됩니다. 실제로 2025년 12월 Dify 플러그인 보고에서는 Nano Banana Pro 프리뷰 버전도 같은 "Image part is missing a thought_signature" 400을 냈습니다.

모델 ID도 함께 점검하십시오. gemini-3.1-flash-image-preview와 gemini-3-pro-image-preview는 2026년 6월 25일에 종료됐고(지원 중단 목록), 위 issue에서 비교 대상이던 gemini-2.5-flash-image도 2026년 10월 2일에 종료됐습니다. 오래된 예제 코드를 그대로 쓰고 있다면 서명 오류보다 먼저 모델 ID 오류를 만나게 됩니다.

함수 호출·에이전트 흐름의 서명 규칙과 skip_thought_signature_validator

함수 호출 서명과 이미지 part 서명을 원래 part에 붙인 채 기록을 보존하는 규칙

Nano Banana 2 이미지 편집이 아니라 Gemini 3 모델의 도구 호출·에이전트 흐름에서 missing thought_signature 400이 났다면, 검증 규칙이 더 구체적입니다. Google Cloud 사고 서명 문서 기준입니다.

  • 턴과 단계: 턴은 사용자의 새 메시지(functionResponse만 담긴 메시지 제외)에서 시작해 모델이 함수 호출이 아닌 최종 답을 낼 때 끝납니다. 그 안에서 함수를 부를 때마다 단계가 하나씩 생깁니다.
  • 순차 호출: 각 단계의 functionCall part에 서명이 붙습니다. 현재 턴의 모든 단계에 대해 첫 번째 functionCall part의 서명을 받은 그대로 돌려보내야 하며, 하나라도 빠지면 400입니다.
  • 병렬 호출: 한 응답에 함수 호출이 여러 개면 첫 번째 functionCall part에만 서명이 붙습니다. 돌려보낼 때는 모든 호출을 먼저, 그 뒤에 모든 응답을 둡니다(FC1+서명, FC2, FR1, FR2). 호출과 응답을 번갈아 두면(FC1, FR1, FC2, FR2) 400입니다.
  • 함수 호출이 아닌 part: 마지막 part에 서명이 붙을 수 있고, 돌려보내는 것이 권장됩니다. 앞 절의 표처럼 Nano Banana 2 이미지 part는 예외적으로 400이 보고돼 있습니다.

skip_thought_signature_validator는 API가 만들지 않은 functionCall part를 기록에 넣어야 할 때를 위한 값입니다. 예를 들어 서명을 주지 않는 다른 모델에서 대화 기록을 옮겨 온 경우, 그 함수 호출 part의 thought_signature에 이 문자열을 넣을 수 있습니다. Google은 모델 성능을 떨어뜨리므로 최후의 수단으로만 쓰라고 적고 있습니다. 이 값을 이미지 part에 써도 된다는 문서는 없으므로, 이미지 편집의 400을 이 문자열로 우회하려 하지 말고 위 세 가지 방법으로 진짜 서명을 돌려주십시오. 다른 이름의 "더미 서명" 문자열도 이미지 part에 쓸 수 있다는 공식 근거가 없습니다.

스트리밍·모델 전환에서 서명이 빠지는 경우

스트리밍에서는 서명이 언제 오는지를 놓치기 쉽습니다.

  • generateContent 스트리밍: Google Cloud 문서에 따르면 서명이 빈 텍스트를 가진 part에 담겨 올 수 있습니다. if chunk.text:처럼 텍스트가 있는 청크만 처리하면 바로 그 part를 버리게 되므로, finish_reason이 올 때까지 모든 청크의 모든 part를 확인해야 합니다.
  • Interactions API 스트리밍: Thinking 가이드 기준으로 thought_signature delta는 해당 step의 step.stop 직전 마지막 delta로 옵니다. 스트림을 중간에 끊으면 서명을 받지 못합니다.

API별 스트리밍 사고 서명 처리 차이와 모든 part를 보존하는 안내

대화 도중 모델을 바꾸는 경우, Interactions API를 무상태 방식으로 쓰고 있다면 이전 모델의 사고 블록도 그대로 다시 보내라고 Thinking 가이드는 안내합니다. 호환성은 백엔드가 처리합니다. 서명을 아예 주지 않는 모델의 기록에 함수 호출이 섞여 있다면 앞 절의 skip_thought_signature_validator가 해당하는 경우입니다.

포럼과 GitHub에는 Thought signature is not valid나 Corrupted thought signature 같은 문구도 보입니다. 서명이 빠진 것이 아니라 값이 달라졌다는 뜻으로 읽히는데, 공식 문서가 원인을 따로 설명하지는 않습니다. 실무에서는 서명 문자열을 다른 인코딩으로 바꿔 저장했거나, 다른 대화나 다른 part의 서명을 붙였거나, part를 합치면서 서명이 섞인 경우를 먼저 의심해 볼 만합니다. 해결 방향은 같습니다. 응답에서 받은 part를 손대지 않고 그대로 돌려주는 것입니다.

서명 오류가 아닌 Nano Banana 이미지 오류는 따로 확인

두 번째 턴이 400이 아니라 200 OK인데 이미지가 없거나, 429·503 같은 다른 코드가 난다면 서명 문제가 아닙니다.

사고 서명 FAQ: thinking 끄기, DB 저장, 더미 서명

thinking을 끄거나 낮추면 Nano Banana 2 사고 서명 오류를 피할 수 있나요?

기대하기 어렵습니다. Google Cloud 문서는 Gemini 3 모델에서 thinking 수준을 MINIMAL로 두더라도 이전 응답의 서명을 돌려보내야 한다고 적고 있습니다. 설정을 바꾸기보다 서명을 그대로 돌려주는 쪽으로 고치십시오.

Nano Banana 2 대화 기록을 DB에 저장했다가 나중에 이어서 편집할 수 있나요?

Interactions API라면 interaction id를 저장해 두고 다음 요청에 previous_interaction_id로 넘기면 됩니다. generateContent라면 모델 턴의 part를 thoughtSignature까지 포함해 받은 그대로 저장하고, 복원할 때도 그대로 넣어야 합니다. 이미지 바이트만 저장해 두었다면 그 이미지를 새 대화의 사용자 입력으로 보내 편집을 시작하는 편이 안전합니다.

이미지 part에 더미 서명 문자열을 넣으면 400을 우회할 수 있나요?

공식 근거가 없습니다. Google이 문서화한 skip_thought_signature_validator는 API가 만들지 않은 functionCall part용이며, 그마저도 성능을 떨어뜨리는 최후의 수단입니다. 이미지 편집에서는 previous_interaction_id, SDK chat, 응답 content 그대로 추가하기 중 하나로 진짜 서명을 돌려주십시오.

공식 문서

요청 파라미터, 가격, 과금 규칙은 LaoZhang API 개발자 문서를 기준으로 합니다: 이미지 생성 과금과 실패 처리.

안내: laozhang.ai는 이 블로그 운영팀의 자사 서비스입니다. 그 가격은 독립적인 비교가 아니라 자사 제시 가격입니다.

참고 자료7

이 글이 링크한 외부 페이지를 본문에 나온 순서대로 정리했습니다. 마지막 업데이트: 2026년 10월 5일.

  1. 1.Thinking 가이드ai.google.dev/gemini-api/docs/thinking
  2. 2.issue #12988github.com/vercel/ai/issues/12988
  3. 3.API 오류 목록ai.google.dev/gemini-api/docs/api-errors
  4. 4.이미지 생성 가이드ai.google.dev/gemini-api/docs/image-generation
  5. 5.사고 서명 문서docs.cloud.google.com/gemini-enterprise-agent-platform/models/thinking/thought-signatures
  6. 6.Dify 플러그인 보고github.com/langgenius/dify-official-plugins/issues/2262
  7. 7.지원 중단 목록ai.google.dev/gemini-api/docs/deprecations
Nano Banana 2 이미지 실패에서 Gemini 앱 안내와 API 응답을 따로 확인하는 개념 그림
문제 해결

Nano Banana 2 작동 안 함? 앱 증상과 API 오류 확인하기

Nano Banana 2 이미지가 안 나오면 앱의 로그인·기능·한도 안내와 API의 모델 ID·오류 응답을 따로 확인하세요. 이미지 없는 HTTP 200이나 타임아웃만으로 원인과 과금을 단정하지 말고, 응답 내용과 이용한 서비스의 사용 내역을 확인해야 합니다.

12 분