Kembali ke panduan
Pemecahan masalah·28 Agustus 2026·Baca 6 menit

Claude API 400 “tool_use ids were found without tool_result blocks” — aturan pengurutan

Ini adalah error pengurutan pesan, bukan error tools. Claude mengharuskan setiap blok tool_use dalam turn assistant dijawab oleh blok tool_result pada turn user yang langsung berikutnya — id yang sama, tanpa apa pun di antaranya. Loop Anda menghilangkan salah satunya, biasanya karena tool mengalami error.

Terakhir ditinjau pada .

Ini adalah error pengurutan pesan, bukan error tools. Claude mengharuskan setiap blok tool_use dalam turn assistant dijawab oleh blok tool_result pada turn user yang langsung berikutnya — id yang sama, tanpa apa pun di antaranya. Loop Anda menghilangkan salah satunya, biasanya karena tool mengalami error.

Error

respons (HTTP 400)
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "messages.1: tool_use ids were found without tool_result blocks immediately after: toolu_01A... Each tool_use block must have a corresponding tool_result block in the next message."
  }
}

Ringkasan penyebab dan perbaikan

PenyebabPerbaikan
Tool Anda mengalami error, sehingga tidak ada yang ditambahkanTetap kirim tool_result, dengan is_error: true dan teks error.
tool_result masuk ke pesan yang lebih baruTool_result harus berada di pesan yang langsung berikutnya — tidak boleh ada turn assistant atau user di antaranya.
tool_use_id tidak cocokSalin id persis dari blok tool_use; jangan membuatnya ulang.
Riwayat dipangkas di tengah perjalanan pulang-pergiPangkas pada batas perjalanan pulang-pergi tool secara utuh, jangan di antara dua bagiannya.

Invarian, dinyatakan sekali

Setiap blok tool_use dalam turn assistant memerlukan tepat satu blok tool_result dalam pesan user yang langsung berikutnya, dengan tool_use_id yang sama. Beberapa blok tool_use dalam satu turn memerlukan beberapa blok tool_result dalam satu pesan berikutnya itu. Tidak boleh ada apa pun di antara kedua turn tersebut.

Selalu balas, bahkan ketika tool gagal

Model dapat menangani tool yang gagal dengan baik; model tidak dapat menangani tool yang hilang. Mengembalikan error sebagai tool_result menjaga percakapan tetap valid dan biasanya menghasilkan pemulihan yang masuk akal, bukan 400.

tool_loop.py
results = []
for block in (b for b in resp.content if b.type == "tool_use"):
    try:
        out = run_tool(block.name, block.input)
        results.append({
            "type": "tool_result",
            "tool_use_id": block.id,
            "content": str(out),
        })
    except Exception as e:
        # A failed tool still owes the model an answer.
        results.append({
            "type": "tool_result",
            "tool_use_id": block.id,
            "content": f"Tool failed: {e}",
            "is_error": True,
        })

messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": results})

Validasikan dua turn terakhir sebelum mengirim

Sekitar selusin baris assertion menangkap ini di lokasi pemanggilan, bukan sebagai 400 dari jaringan — telusuri id tool_use pada turn assistant dan pastikan turn user berikutnya menjawab semuanya.

validate.py
def check_pairs(messages):
    for i, m in enumerate(messages):
        if m["role"] != "assistant" or not isinstance(m.get("content"), list):
            continue
        ids = {b.get("id") for b in m["content"]
               if isinstance(b, dict) and b.get("type") == "tool_use"}
        if not ids:
            continue
        nxt = messages[i + 1] if i + 1 < len(messages) else None
        answered = {b.get("tool_use_id") for b in (nxt or {}).get("content", [])
                    if isinstance(b, dict) and b.get("type") == "tool_result"}
        missing = ids - answered
        assert not missing, f"message {i}: unanswered tool_use {missing}"

Pangkas riwayat pada batas perjalanan pulang-pergi

Pemangkasan context window berdasarkan jumlah pesan pada akhirnya akan memotong di antara tool_use dan tool_result. Perlakukan pasangan tersebut sebagai satu unit yang tidak dapat dipisahkan saat menentukan apa yang akan dihapus.

Jika Anda melakukan panggilan melalui Kunavo

Payload ini adalah tanggung jawab Anda, dan Kunavo tidak menutupinya: 400 termasuk dalam daftar yang tidak dapat di-retry, sehingga perjalanan tool yang malformasi gagal sekali alih-alih menghabiskan perjalanan pulang-pergi kedua ke upstream hanya untuk mencapai error yang sama, dan request yang ditolak dicatat dengan biaya nol. Pada /v1/messages Anda berbicara langsung menggunakan protokol Messages, sehingga blok tools, tool_use, dan tool_result diteruskan tanpa diterjemahkan. Di sana 400 dikembalikan dengan tipe invalid_request_error, seperti pada API Anthropic, disertai teks pesan upstream lalu request id milik upstream dan tanpa field request_id; hingga 24 September 2026 tipenya terbaca api_error, jadi gunakan status HTTP dan teks pesan sebagai cabang jika log Anda mencakup periode sebelumnya.

Pertanyaan umum

Bisakah saya menghapus turn tool_use begitu saja alih-alih menjawabnya?

Ya, jika Anda menghapus seluruh turn assistant. Yang tidak valid adalah mempertahankan tool_use dan menghilangkan tool_result-nya.

Apakah endpoint OpenAI-compatible memiliki aturan yang sama?

Pasangan yang sama tetap diperlukan, dengan penamaan berbeda — tool_calls pada pesan assistant, lalu satu pesan role: "tool" untuk setiap pemanggilan yang membawa tool_call_id.

Apakah request yang ditolak dikenai biaya?

Di Kunavo, tidak. Request yang gagal dicatat dengan biaya nol dan tidak pernah mencapai pemanggilan upstream yang ditagihkan.

Panduan terkait

Detail semantik error lainnya tersedia di referensi error; mendapatkan kunci hanya perlu satu menit melalui pendaftaran dan panduan autentikasi.