Claude Platform Docs
MensagensConstruindo com o Claude

Motivos de parada e fallback

Saiba o que cada valor de stop_reason significa e como lidar com truncamento, uso de ferramentas, turnos pausados e recusas na sua aplicação.

Toda resposta da Messages API inclui um campo stop_reason que informa por que Claude parou de gerar. Verifique esse campo para decidir se deve usar a resposta como está, continuar a conversa, tentar novamente ou fazer fallback para outro modelo.

Para o esquema completo da resposta, consulte a referência da Messages API.

Referência rápida

ValorQuando ocorreO que fazer
end_turnClaude terminou sua resposta naturalmente.Use a resposta.
max_tokensA resposta atingiu seu limite de max_tokens.Aumente max_tokens ou continue a resposta.
stop_sequenceClaude emitiu uma das suas stop_sequences.Leia stop_sequence para ver qual foi acionada.
tool_useClaude está chamando uma ferramenta.Execute a ferramenta e retorne o resultado. Uma chamada de ferramenta de servidor ainda sem seu bloco de resultado é concluída em uma resposta posterior.
pause_turnUm loop de ferramenta de servidor atingiu seu limite de iterações.Envie o conteúdo do assistente de volta para continuar.
refusalClaude se recusou a responder.Leia stop_details e tente novamente em um modelo de fallback.
model_context_window_exceededA resposta preencheu a janela de contexto do modelo.Trate a resposta como truncada.

O campo stop_reason

O campo stop_reason faz parte de toda resposta bem-sucedida da Messages API. Diferentemente dos erros, que indicam falhas no processamento da sua requisição, stop_reason informa por que Claude concluiu a geração da resposta.

Example response
{
  "id": "msg_01234",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "Here's the answer to your question..."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "stop_details": null,
  "usage": {
    "input_tokens": 100,
    "output_tokens": 50
  }
}

Valores de stop reason

end_turn

O motivo de parada mais comum. Indica que Claude terminou sua resposta naturalmente.

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)
if response.stop_reason == "end_turn":
    # Processa a resposta completa
    for block in response.content:
        if block.type == "text":
            print(block.text)

max_tokens

Claude parou porque atingiu o limite de max_tokens especificado na sua requisição.

client = anthropic.Anthropic()
# Requisição com tokens limitados
response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=10,
    messages=[{"role": "user", "content": "Explain quantum physics"}],
)

if response.stop_reason == "max_tokens":
    # A resposta foi truncada
    print("Response was cut off at token limit")
    # Considere fazer outra requisição para continuar

stop_sequence

Claude encontrou uma das suas sequências de parada personalizadas.

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    stop_sequences=["END", "STOP"],
    messages=[{"role": "user", "content": "Generate text until you say END"}],
)

if response.stop_reason == "stop_sequence":
    print(f"Stopped at sequence: {response.stop_sequence}")

tool_use

Claude está chamando uma ferramenta e espera que você a execute.

client = anthropic.Anthropic()
weather_tool = {
    "name": "get_weather",
    "description": "Get the current weather in a given location",
    "input_schema": {
        "type": "object",
        "properties": {
            "location": {"type": "string", "description": "City and state"},
        },
        "required": ["location"],
    },
}


def execute_tool(name, tool_input):
    """Execute a tool and return the result."""
    return f"Weather in {tool_input.get('location', 'unknown')}: 72°F"


response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    tools=[weather_tool],
    messages=[{"role": "user", "content": "What is the weather in San Francisco?"}],
)

if response.stop_reason == "tool_use":
    # Extrai e executa a ferramenta
    for block in response.content:
        if block.type == "tool_use":
            result = execute_tool(block.name, block.input)
            # Retorna o resultado ao Claude para a resposta final

Uma resposta tool_use também pode conter um bloco server_tool_use cujo id não tem um bloco de resultado correspondente. Essa chamada de ferramenta de servidor não está concluída, e essa resposta não traz seu resultado. No caso comum, Claude chama uma ferramenta de servidor e uma das suas ferramentas de cliente no mesmo grupo de chamadas de ferramentas paralelas: a API retorna sem executar a ferramenta de servidor para que você possa executar as ferramentas de cliente primeiro. Não há outro marcador para esse estado; detecte-o verificando se o id de cada bloco server_tool_use ou mcp_tool_use tem um bloco de resultado correspondente.

A mixed tool_use response
{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "server_tool_use",
      "id": "srvtoolu_01HxbWnMRmbWyMfUtJKC45rA",
      "name": "web_search",
      "input": { "query": "example article" }
    },
    {
      "type": "tool_use",
      "id": "toolu_01PjgRJLbXrXEMZwDNYLnBqk",
      "name": "run_command",
      "input": { "command": "uname -a" }
    }
  ]
}

A continuação é uma mensagem de usuário com blocos tool_result, um para cada bloco tool_use na resposta (consulte Lidar com chamadas de ferramentas), com duas regras extras: essa mensagem não deve conter nada além dos blocos tool_result, e a requisição deve manter o mesmo array tools. Uma requisição de retomada que não define mais a ferramenta de servidor em espera falha com um 400 cuja mensagem termina com but no `web_search` tool was provided. A API anexa seus resultados ao turno do assistente ainda aberto, executa a ferramenta de servidor adiada (para execução de código pausada, a retoma) e continua o turno. Para uma ferramenta de servidor que Claude chamou diretamente, o content da próxima resposta começa com o bloco de resultado que responde ao id do server_tool_use da resposta anterior.

The follow-up user message
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01PjgRJLbXrXEMZwDNYLnBqk",
      "content": "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
    }
  ]
}

Adicionar qualquer coisa após os blocos tool_result nessa mensagem de usuário, como texto, encerra o turno do assistente; para uma ferramenta de servidor que Claude chamou diretamente, a requisição então falha com um 400 invalid_request_error que nomeia a ferramenta de servidor não resolvida:

`web_search` tool use with id `srvtoolu_01HxbWnMRmbWyMfUtJKC45rA` was found without a corresponding `web_search_tool_result` block

Omitir um tool_result, ou colocar um após outro conteúdo, falha antes com o erro padrão tool_use ids were found without tool_result blocks immediately after. Para dar mais entrada a Claude, envie-a como uma mensagem de usuário separada após a conclusão do turno.

pause_turn

Retornado quando o loop de amostragem do lado do servidor atinge seu limite de iterações ao executar ferramentas de servidor, como a busca na web. O limite padrão é de 10 iterações por requisição.

Quando isso acontece, a resposta pode conter um bloco server_tool_use sem um bloco de resultado correspondente. Para permitir que Claude termine o processamento, continue a conversa enviando a resposta de volta como está. Uma resposta que deixa um bloco tool_use de cliente aguardando você nunca tem um stop_reason de pause_turn: quando Claude para a fim de chamar suas ferramentas, o stop_reason é tool_use, e você a continua enviando os blocos tool_result de cliente em vez da própria resposta.

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=4096,
    tools=[{"type": "web_search_20250305", "name": "web_search"}],
    messages=[{"role": "user", "content": "Search for latest AI news"}],
)

if response.stop_reason == "pause_turn":
    # Continue a conversa enviando a resposta de volta
    messages = [
        {"role": "user", "content": "Search for latest AI news"},
        {"role": "assistant", "content": response.content},
    ]
    continuation = client.messages.create(
        model="claude-opus-5-5",
        max_tokens=4096,
        messages=messages,
        tools=[{"type": "web_search_20250305", "name": "web_search"}],
    )

refusal

Claude se recusou a gerar uma resposta. Os classificadores de segurança retornam esse motivo de parada como uma resposta HTTP 200 normal, não como um erro.

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "[Unsafe request]"}],
)

if response.stop_reason == "refusal":
    # Claude se recusou a responder
    print("Claude was unable to process this request")
    # Considere reformular ou modificar a solicitação

Em uma recusa, o objeto stop_details identifica a categoria de política que a acionou. As categorias e o formato completo da resposta de recusa são abordados em Recusas e fallback. stop_details é null para todos os motivos de parada que não sejam refusal.

Uma requisição recusada no Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Sonnet 5.5 ou Claude Haiku 5.5 geralmente pode ser atendida tentando novamente em outro modelo Claude. Recusas e fallback mostra como configurar essa nova tentativa, no lado do servidor ou no seu cliente. O Claude Haiku 5.5 não tem fallback no lado do servidor, então configure a nova tentativa dele no seu cliente. Se você mesmo criar a nova tentativa a partir do Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5 ou Claude Sonnet 5.5, o crédito de fallback explica como evitar pagar duas vezes o custo do cache de prompt.

model_context_window_exceeded

Claude parou porque atingiu o limite da "context window" (janela de contexto) do modelo. Isso permite que você solicite o máximo possível de tokens sem saber o tamanho exato da entrada.

# Requisição com o máximo de tokens para obter o máximo possível
response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=20000,  # Python SDK requires streaming for max_tokens above ~21k
    messages=[
        {"role": "user", "content": "Large input that uses most of context window..."}
    ],
)

if response.stop_reason == "model_context_window_exceeded":
    # A resposta atingiu o limite da janela de contexto antes de max_tokens
    print("Response reached model's context window limit")
    # A resposta ainda é válida, mas foi limitada pela janela de contexto

Melhores práticas para lidar com motivos de parada

Sempre verifique o stop_reason

Crie o hábito de verificar o stop_reason na sua lógica de tratamento de respostas:

def handle_response(response):
    match response.stop_reason:
        case "tool_use":
            return handle_tool_use(response)
        case "max_tokens":
            return handle_truncation(response)
        case "model_context_window_exceeded":
            return handle_context_limit(response)
        case "pause_turn":
            return handle_pause(response)
        case "refusal":
            return handle_refusal(response)
        case _:
            # Trata end_turn e outros casos
            return next(
                (block.text for block in response.content if block.type == "text"),
                "",
            )

Lide com respostas truncadas de forma elegante

Quando uma resposta é truncada por causa de limites de tokens ou da janela de contexto, acrescente um aviso para que o leitor saiba que a saída está incompleta. Para, em vez disso, continuar gerando a partir de onde a resposta parou, consulte Garantindo respostas completas.

def handle_truncated_response(response):
    text = next((block.text for block in response.content if block.type == "text"), "")
    if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
        if response.stop_reason == "max_tokens":
            note = "[Response truncated due to max_tokens limit]"
        else:
            note = "[Response truncated due to context window limit]"
        return f"{text}\n\n{note}"
    return text

Implemente lógica de nova tentativa para pause_turn

Ao usar ferramentas de servidor, a API pode retornar pause_turn se o loop de amostragem do lado do servidor atingir seu limite de iterações (padrão 10). Lide com isso continuando a conversa:

def handle_server_tool_conversation(client, user_query, tools, max_continuations=5):
    """
    Handle server tool conversations that may require multiple continuations.

    The server runs a sampling loop when executing server tools. If the loop
    reaches its iteration limit, the API returns pause_turn. Continue the
    conversation by sending the response back to let Claude finish.
    """
    messages = [{"role": "user", "content": user_query}]

    for _ in range(max_continuations):
        response = client.messages.create(
            model="claude-opus-5-5",
            max_tokens=4096,
            messages=messages,
            tools=tools,
        )

        if response.stop_reason != "pause_turn":
            # Claude terminou o processamento - retorna a resposta final
            return response

        # pause_turn: substitui a lista completa de mensagens para manter a alternância de papéis
        messages = [
            {"role": "user", "content": user_query},
            {"role": "assistant", "content": response.content},
        ]

    # Limite máximo de continuações atingido - retorna a última resposta
    return response

Motivos de parada vs. erros

É importante distinguir entre valores de stop_reason e erros reais:

Motivos de parada (respostas bem-sucedidas)

  • Fazem parte do corpo da resposta
  • Indicam por que a geração parou normalmente
  • A resposta contém conteúdo válido

Erros (requisições com falha)

  • Códigos de status HTTP 4xx ou 5xx
  • Indicam falhas no processamento da requisição
  • A resposta contém detalhes do erro
client = anthropic.Anthropic()

try:
    response = client.messages.create(
        model="claude-opus-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    )

    # Trata a resposta bem-sucedida com stop_reason
    if response.stop_reason == "max_tokens":
        print("Response was truncated")

except anthropic.APIStatusError as e:
    # Trata os erros reais
    match e.status_code:
        case 429:
            print("Rate limit exceeded")
        case 500:
            print("Server error")

Considerações sobre streaming

Ao usar streaming, o stop_reason é:

  • null no evento inicial message_start
  • Fornecido no evento message_delta
  • Não fornecido em nenhum outro evento
client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
) as stream:
    for event in stream:
        if event.type == "message_delta":
            stop_reason = event.delta.stop_reason
            if stop_reason:
                print(f"Stream ended with: {stop_reason}")

Padrões comuns

Lidando com fluxos de trabalho de uso de ferramentas

def complete_tool_workflow(client, user_query, tools):
    messages = [{"role": "user", "content": user_query}]

    while True:
        response = client.messages.create(
            model="claude-opus-5-5",
            max_tokens=1024,
            messages=messages,
            tools=tools,
        )

        if response.stop_reason == "tool_use":
            # Executa as ferramentas e continua
            tool_results = execute_tools(response.content)
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})
        else:
            # Resposta final
            return response

Garantindo respostas completas

def get_complete_response(client, prompt, max_attempts=3):
    messages = [{"role": "user", "content": prompt}]
    full_response = ""

    for _ in range(max_attempts):
        response = client.messages.create(
            model="claude-opus-5-5", messages=messages, max_tokens=4096
        )

        full_response += next(
            (block.text for block in response.content if block.type == "text"), ""
        )

        if response.stop_reason != "max_tokens":
            break

        # Continua de onde parou
        messages = [
            {"role": "user", "content": prompt},
            {"role": "assistant", "content": full_response},
            {"role": "user", "content": "Please continue from where you left off."},
        ]

    return full_response

Obtendo o máximo de tokens sem saber o tamanho da entrada

Com o motivo de parada model_context_window_exceeded, você pode solicitar o máximo possível de tokens sem calcular o tamanho da entrada:

def get_max_possible_tokens(client, prompt):
    """
    Get as many tokens as possible within the model's context window
    without needing to calculate input token count
    """
    response = client.beta.messages.create(
        model="claude-opus-5-5",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=20000,  # Python SDK requires streaming for max_tokens above ~21k
    )

    match response.stop_reason:
        case "model_context_window_exceeded":
            # Obteve o máximo de tokens possível dado o tamanho da entrada
            print(
                f"Generated {response.usage.output_tokens} tokens (context limit reached)"
            )
        case "max_tokens":
            # Obteve exatamente os tokens solicitados
            print(
                f"Generated {response.usage.output_tokens} tokens (max_tokens reached)"
            )
        case _:
            # Conclusão natural
            print(
                f"Generated {response.usage.output_tokens} tokens (natural completion)"
            )

    return next((block.text for block in response.content if block.type == "text"), "")

Próximos passos

Tente novamente requisições recusadas em um modelo de fallback, no lado do servidor ou no seu cliente.

Deixe o SDK gerenciar o loop de tool_use, a formatação de resultados e as novas tentativas para você.

Leia o stop_reason do evento message_delta ao usar streaming.

Lide com erros HTTP 4xx e 5xx, que são distintos dos motivos de parada.

Was this page helpful?