Claude 400 오류: tool_use에 맞는 tool_result가 없을 때
Claude와 OpenCode의 tool_result 오류에서 호출 ID, 메시지 순서, 병렬 결과와 중단된 세션을 재시도 전에 확인하는 방법입니다.
Claude에서 tool_use에 대응하는 tool_result가 없다고 나오면 보통 프롬프트 표현보다 도구 대화 구조를 확인해야 합니다. 네이티브 Messages API에서는 assistant가 클라이언트 도구를 호출하고 바로 다음 user 메시지가 같은 ID의 결과를 반환합니다. 같은 요청을 다시 보내기 전에 이 관계를 검사하세요.
이 글은 직접 만든 통합과 OpenCode 같은 클라이언트에서 이 오류 유형을 다룹니다. OpenCode의 모든 HTTP 400이 같은 원인은 아닙니다. 2026년 9월 14일 확인한 Claude 도구 호출 처리 문서를 따릅니다. 예시는 합성 메시지 조각이며 실제 API 테스트 로그가 아닙니다.
짝이 없는 ID부터 찾기
전체 오류를 읽고 지목된 tool-use ID를 앞선 assistant 메시지에서 찾으세요. 이어지는 user 메시지의 tool_result.tool_use_id가 정확히 일치해야 합니다. 도구 이름은 호출 식별자를 대신하지 않습니다.
Claude 네이티브 프로토콜에서 도구 결과는 user 메시지의 content 블록입니다. 이 형태에는 네이티브 role: "tool"이 없습니다. 다른 제공업체도 지원하는 어댑터라면 역할과 필드를 그대로 전달하지 않고 변환하는지 확인하세요.
| 검사 항목 | 올바른 관계 | 흔한 실패 |
|---|---|---|
| 식별자 | tool_use.id와 tool_result.tool_use_id 일치 | 새 ID 또는 잘린 ID |
| 메시지 순서 | assistant 호출 바로 뒤 user 결과 | 중간에 다른 메시지 삽입 |
| 여러 호출 | 모든 클라이언트 호출에 결과 존재 | 첫 결과만 저장 |
| user content 순서 | 일반 텍스트보다 도구 결과가 먼저 | 텍스트가 결과 앞에 위치 |
최소한의 올바른 메시지 예시
이 JSON은 관련 메시지만 보여 줍니다. 전체 요청에는 모델, 도구 정의, 토큰 한도와 나머지 대화도 필요합니다. 예시 결과는 설명을 위해 만든 값이며 실제 도구 실행을 대체해서는 안 됩니다.
[
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "toolu_demo", "name": "lookup", "input": {"key": "demo"}}
]
},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "toolu_demo", "content": "demo result"}
]
}
]
채팅창의 표시 텍스트로 assistant 메시지를 다시 만들지 마세요. API가 반환한 전체 구조를 저장해야 합니다. 모델과 워크플로에 따라 추론 데이터 등 다른 블록도 필요합니다. 서명 검증은 별개 문제이며 Claude thinking 서명 안내에서 설명합니다.
병렬 호출은 결과 전체를 함께 반환하기
한 assistant 메시지가 클라이언트 도구 두 개를 요청했다면 두 결과를 모아 바로 다음 user 메시지에 넣으세요. 첫 결과 뒤에 assistant 턴을 끼우고 나중에 이전 호출의 두 번째 결과를 보내면 안 됩니다. 허용되는 설명 텍스트는 결과 블록 뒤에 둡니다.
공식 문제 해결 문서는 서버 도구와 섞인 흐름도 다룹니다. 같은 라운드에 미완료 서버 도구가 남아 있다면 user 메시지는 클라이언트 결과만 포함하고 요청은 tools 배열을 유지해야 합니다. 최소 클라이언트 예제를 모든 서버 도구 흐름에 일반화하지 마세요.
실패 결과를 사실대로 반환하기
조회나 명령 실행에 실패해도 도구 결과의 짝은 올바르게 만들 수 있습니다. 문서에 정해진 클라이언트 도구 형식에 따라 같은 ID, is_error: true, 정확한 실패 설명을 반환하세요. 프로토콜 관계와 작업 성공은 별도 검사입니다.
클라이언트가 중단됐다면 도구가 실제로 실행됐는지 먼저 확인하세요. 화면의 타임아웃은 파일 쓰기, 배포, 외부 요청이 일어나지 않았다는 증거가 아닙니다. 부작용이 있는 동작을 반복하기 전에 상태를 검사하세요. 검증을 통과시키려고 성공 결과를 만들거나 중요한 도구를 자동으로 두 번 실행하면 안 됩니다.
개발 중에는 임시 세션에서 무해한 조회로 재현하세요. 읽기 전용 사례로도 쓰기 작업이나 거래를 반복할 위험 없이 짝 맞춤 오류를 찾을 수 있습니다. 클라이언트 버전과 중단 직전·직후 메시지를 저장하세요.
손상된 세션 복구하기
수정하기 전에 관련 이력의 로컬 복사본을 보관하세요. 원래 결과가 있다면 클라이언트가 지원하는 복구 방식으로 올바른 메시지 쌍을 복원합니다. 안전하게 복구할 수 없으면 검증된 작업과 남은 동작을 짧게 정리해 새 세션을 만들고 이전 세션도 보관하세요.
도구 블록을 임의로 지우면 모델이 이해하는 실행 상태가 달라질 수 있습니다. 모든 대화 파일 삭제는 기본 해결책이 아닙니다. issue에는 역할, content 유형, ID를 보여 주는 민감정보를 제거한 작은 재현 사례를 제공하고 API 키, 비공개 인수와 결과를 제거하세요.
업데이트는 릴리스 노트를 확인할 가치가 있지만 이 글이 모든 사례를 해결하는 특정 버전을 제시하지는 않습니다. 과거 issue는 당시 구성에서 오류가 있었다는 증거이지 최신판에도 같은 버그가 있다는 증거는 아닙니다.
재시도만으로 해결되지 않는 이유
API는 모델 턴을 이어 가기 전에 대화 구조를 검증합니다. 같은 불일치 메시지를 다시 보내면 구조 문제도 그대로입니다. 이는 프로토콜 규칙에 따른 판단이며 모든 클라이언트의 재시도 구현을 실측한 결과는 아닙니다.
HTTP 429나 서비스 과부하는 별도로 조사해야 합니다. 이 절차를 적용하기 전에 상태 코드와 오류 본문을 확인하세요. 다른 접근 문제는 model-not-found 진단 (영문)을 참고할 수 있지만 다른 프로토콜을 다루므로 Claude 도구 메시지 짝과 혼동하지 마세요.
자주 묻는 질문
도구 오류를 반환해도 짝 맞춤 조건을 만족하나요?
예. 실제 실패 설명도 원래 tool-use ID에 연결할 수 있습니다. 작업 성공 여부와 다음 메시지에서 실패를 올바르게 표현하는 것은 별개입니다.
네이티브 Claude API에 role tool을 쓰나요?
아닙니다. 클라이언트 도구 결과는 user 메시지의 content 블록입니다. OpenAI 호환 어댑터는 다른 형태일 수 있으므로 요청을 받는 엔드포인트의 프로토콜을 따르세요.
새 세션이면 완전히 해결되나요?
손상된 이력은 분리할 수 있지만 결과를 계속 버리는 어댑터는 고치지 못합니다. 깨진 순서를 만든 직렬화 코드나 클라이언트 경로도 확인해야 합니다.
자주 묻는 질문
- 도구 오류를 반환해도 짝 맞춤 조건을 만족하나요?
- 예. 실제 실패 설명도 원래 tool-use ID에 연결할 수 있습니다. 작업 성공 여부와 다음 메시지에서 실패를 올바르게 표현하는 것은 별개입니다.
- 네이티브 Claude API에 role tool을 쓰나요?
- 아닙니다. 클라이언트 도구 결과는 user 메시지의 content 블록입니다. OpenAI 호환 어댑터는 다른 형태일 수 있으므로 요청을 받는 엔드포인트의 프로토콜을 따르세요.
- 새 세션이면 완전히 해결되나요?
- 손상된 이력은 분리할 수 있지만 결과를 계속 버리는 어댑터는 고치지 못합니다. 깨진 순서를 만든 직렬화 코드나 클라이언트 경로도 확인해야 합니다.


