---
title: "Código Apenas do Caminho Feliz"
type: "ai-smell"
slug: "happy-path-only"
url: "http://localhost:3000/pt-br/ai-smells/happy-path-only.md"
category: "Corretude"
description: "Assistentes de IA tendem a gerar código que trata apenas o caso bem-sucedido e bem-formado — pulando validação de entrada, tratamento de erros, verificações de nulo/vazio e casos extremos — de modo que o código funciona na demonstração e quebra em produção."
---
# Código Apenas do Caminho Feliz

> Assistentes de IA tendem a gerar código que trata apenas o caso bem-sucedido e bem-formado — pulando validação de entrada, tratamento de erros, verificações de nulo/vazio e casos extremos — de modo que o código funciona na demonstração e quebra em produção.

## Signs and Symptoms

Um revisor identifica código apenas do caminho feliz quando cada linha assume que a anterior teve sucesso: chamadas de rede não são verificadas quanto a status diferente de 2xx, `JSON.parse`/`await res.json()` nunca é encapsulado, campos anuláveis são desreferenciados diretamente, arrays são indexados sem verificar o tamanho e a entrada externa flui direto para a lógica sem nenhuma validação. Em geral há exatamente um caminho de retorno e nenhum `throw`, nenhuma cláusula de guarda e nenhum `catch` (ou um `catch` que está vazio ou apenas com `console.log`).

```ts
// Gerado por IA: apenas o cenário de sucesso existe
async function getUserCity(userId) {
  const res = await fetch(`/api/users/${userId}`);
  const user = await res.json();
  return user.address.city.toUpperCase();
}

```

Modos de falha silenciosamente ausentes: `res.ok` nunca é verificado (404/500 retorna um corpo de erro que `.json()` pode rejeitar), `user` poderia ser `{}`, `address` poderia ser `null`, `city` poderia ser `undefined` → `Cannot read properties of undefined`. A função "funciona" contra um stub feliz e lança erro contra a realidade.

Sinais reveladores em um diff:

* Uma nova função `async` sem `try`/`catch` e sem `.catch()` na promise.
* Cadeias de propriedades diretas (`a.b.c.d`) sobre dados que cruzaram uma fronteira de confiança/IO.
* `arr[0]` sem verificação, `find(...)!`, casts `as` ou asserções de não-nulo (`!`) no lugar de um tratamento real.
* `// TODO: handle errors` ou um `catch (e) {}` vazio deixado como espaço reservado.
* A descrição do PR diz "trata X", mas apenas o ramo em que X dá certo está implementado.

## Reasons for the Problem

**Por que os modelos produzem isso**

* **A probabilidade do próximo token favorece o fluxo canônico.** A continuação mais provável depois de `const user = await res.json()` é `return user.something` — não uma verificação de status. O tratamento de erros é um boilerplate de alta variância que muda de uma base de código para outra, então é estatisticamente "surpreendente" e acaba descartado.
* **Os dados de treinamento são enviesados para o caminho feliz.** Tutoriais, trechos de README, posts de blog e respostas aceitas no Stack Overflow removem validação e tratamento de erros por brevidade ("tratamento de erros omitido por clareza"). O modelo aprendeu com textos que deliberadamente removeram justamente o código que você quer.
* **Bajulação / recompensa por parecer limpo.** Assistentes ajustados por RLHF são recompensados por respostas concisas e diretamente responsivas. Código defensivo parece ruído, então o modelo otimiza para o trecho arrumado que aparenta responder ao prompt.
* **Sem contexto do repositório.** O modelo não sabe que você tem um tipo `AppError`, um wrapper `Result<T>`, um esquema `zod` ou uma convenção de logging, então não consegue reutilizá-los — e recorre por padrão a "nada" em vez de adivinhar suas convenções.
* **Tendências comportamentais documentadas.** A análise da OX Security de mais de 300 repositórios cita _Evitação de Refatorações_ e _Fixação no Manual_ entre seus principais antipadrões de IA — o modelo produz código funcional para o prompt imediato e nunca o robustece. O arXiv 2509.20491 cataloga smells específicos de IA em torno de _falhas silenciosas_; o arXiv 2510.03029 encontra smells de implementação elevados, como _Bloco Catch Vazio_, na saída de LLMs.

**Por que isso é prejudicial**

* **Correção:** quebra com `null`, coleções vazias, timeouts e respostas diferentes de 200 — exatamente as entradas que não aparecem em um teste manual rápido.
* **Segurança:** o caminho feliz confia implicitamente em sua entrada. Validação ignorada nas fronteiras é a porta por onde entram bugs de injeção, path traversal e prototype pollution. O relatório da OX descreve isso como código "inseguro por burrice," entregue rápido e sem critério.
* **Carga de revisão e depuração:** na Stack Overflow Developer Survey de 2025, 66% dos desenvolvedores citam "soluções de IA que estão quase certas, mas não totalmente" como sua maior frustração e 45% dizem que depurar código gerado por IA consome _mais_ tempo. O código de caminho feliz é o arquétipo do "quase certo" — lê-se bem e falha em tempo de execução.
* **Acúmulo de dívida técnica:** como o modelo não refatora nem reutiliza utilitários de erro existentes, cada função de caminho feliz é um novo bloco de uso único. Os dados de 2025 da GitClear mostram o padrão mais amplo — linhas copiadas/coladas subiram de 8,3% (2021) para 12,3% (2024), blocos duplicados de 5+ linhas cresceram \~8x em 2024, enquanto a refatoração (linhas movidas) caiu de \~25% para menos de 10%. O tratamento de erros ausente é remendado depois, duplicado em cada ponto de chamada, nunca centralizado.

## Treatment

**Táticas de revisão e de prompting**

* **Faça o modelo enumerar os modos de falha primeiro.** Prompt: "Antes de escrever código, liste os modos de falha desta função (entrada inválida, erro de rede, status diferente de 200, resposta vazia/malformada, campos ausentes, concorrência). Depois implemente o tratamento de cada um." Forçar a etapa de enumeração contraria a tendência do próximo token de ignorá-los.
* **Aponte as convenções a reutilizar.** "Use nosso tipo `AppError`/`Result` existente de `lib/errors.ts` e o `logger` de `lib/log.ts`; valide a resposta com o esquema `zod` em `schemas/user.ts`." Isso converte "sem tratamento" em reutilização em vez de um bloco sob medida (evita _Código Duplicado_).
* **Exija que os portões sejam executados.** "Rode `eslint` e `tsc --noEmit` e corrija cada aviso, incluindo `@typescript-eslint/no-floating-promises`." A verificação de tipos com `strictNullChecks` transforma desreferências silenciosas de nulo em erros de compilação que o modelo precisa resolver.
* **Exija os testes negativos.** Peça testes unitários cobrindo as entradas vazias/nulas/de erro, não apenas o caso feliz — a ausência desses testes é, por si só, o smell.

**A refatoração**

Adicione validação de fronteira e cláusulas de guarda, e centralize o tratamento. Movimentos nomeados: **Introduzir Cláusula de Guarda** (`throw` antecipado em estado inválido), **Introduzir Asserção / validação de fronteira** (parse-don't-validate nas bordas de IO) e **Introduzir Caso Especial / Objeto Nulo** (`?? "UNKNOWN"` em vez de quebrar).

```ts
// depois: os modos de falha são cidadãos de primeira classe
async function getUserCity(userId: string): Promise<string> {
  if (!userId) throw new InvalidArgumentError("userId required");   // cláusula de guarda

  const res = await fetch(`/api/users/${encodeURIComponent(userId)}`);
  if (!res.ok) throw new ApiError(`user fetch failed: ${res.status}`);

  const user = UserSchema.parse(await res.json());                  // validar na fronteira
  return user.address?.city?.toUpperCase() ?? "UNKNOWN";           // trata a lacuna como caso especial
}

```

Se o mesmo padrão de try/validar/log começar a se repetir em vários pontos de chamada, faça **Extrair Função** dele em um helper compartilhado `fetchJson<T>(url, schema)` para que o tratamento de erros viva em um só lugar em vez de ser copiado e colado (a armadilha de duplicação da GitClear).

## Detected by

- **typescript-eslint** `@typescript-eslint/no-floating-promises` — Sinaliza promises cujo caminho de rejeição nunca é tratado (sem await/catch) — um sintoma comum de caminho feliz em chamadas assíncronas. (https://typescript-eslint.io/rules/no-floating-promises/)
- **ESLint** `no-empty` — Sinaliza blocos vazios, incluindo blocos catch vazios — o 'tratamento de erros' de fachada que o modelo deixa para trás. (https://eslint.org/docs/latest/rules/no-empty)
- **SonarSource (JS/TS)** `javascript:S2486` — Exceções não devem ser ignoradas — sinaliza erros capturados mas engolidos, o primo degenerado da ausência total de tratamento. (https://rules.sonarsource.com/javascript/RSPEC-2486/)
