---
name: build-errors-rust
description: >
  Resolución de errores de compilación Rust: cargo build, clippy, borrow checker
  y lifetimes. Incluye errores de trait bounds, async y feature flags.
  Cargar cuando un build Rust falle o haya errores del borrow checker, lifetimes
  o compilación de crates.
version: "1.0.0"
herramientasPermitidas: [Read, Bash, Grep]
exclusiones:
  - "No cargar para panics en runtime (unwrap() en None, index out of bounds en ejecución) — si `cargo build` pasa pero el programa panics, es un error lógico; diagnosticar con `RUST_BACKTRACE=1`."
  - "No cargar para diseñar la arquitectura de crates en un workspace Rust — si la pregunta es cómo estructurar un workspace multi-crate o qué crates separar, cargar `rust-patrones` o `rust-experto`."
  - "No cargar para fallos de tests que son correctos a nivel de compilación (assert_eq! con valor incorrecto) — si `cargo test --no-run` pasa pero los tests fallan, es un error de lógica de tests."
  - "No cargar para problemas de rendimiento de Rust detectados en profiling — si el código compila y es correcto pero es lento, no es un error de build; usar flamegraph y profiling."
evolvable: true  # default para skill estandar
---
# Build Errors Rust — Diagnóstico y Solución

## Cuándo NO cargar

- El programa compila pero panics en runtime (`unwrap()` en `None`, OOB index) — no es un error de compilación; diagnosticar con `RUST_BACKTRACE=1`.
- Los tests fallan por `assert_eq!` con valor incorrecto aunque `cargo test --no-run` pasa — es un error de lógica, no de build.
- La pregunta es cómo estructurar un workspace o separar crates — para arquitectura cargar `rust-patrones`.

## Cuándo cargar

- `cargo build` o `cargo test` falla con mensajes del compilador
- Errores del borrow checker (`cannot borrow`, `value moved`, `does not live long enough`)
- Errores de lifetime (`missing lifetime specifier`, `conflicting requirements`)
- Errores de trait bounds (`the trait X is not implemented for Y`)
- Warnings de clippy que bloquean CI con `RUSTFLAGS="-D warnings"`
- Errores de features o dependencias de crates

---

## Borrow Checker — Errores Más Frecuentes

### `cannot borrow as mutable because it is also borrowed as immutable`

**Causa**: se intenta mutar un valor mientras existe una referencia inmutable viva.

```rust
// MAL
let mut v = vec![1, 2, 3];
let first = &v[0];   // referencia inmutable activa
v.push(4);           // error: mutacion mientras existe referencia
println!("{first}");

// BIEN: acotar el lifetime de la referencia inmutable
let mut v = vec![1, 2, 3];
{
    let first = &v[0];
    println!("{first}");
}  // referencia inmutable cae aquí
v.push(4);
```

### `value used after move`

**Causa**: un tipo sin `Copy` se mueve a otra variable o función y luego se usa.

```rust
// MAL
let s = String::from("hola");
let s2 = s;         // s se mueve a s2
println!("{s}");    // error: s fue movido

// BIEN — opción 1: clonar si se necesitan dos copias independientes
let s2 = s.clone();
println!("{s} {s2}");

// BIEN — opción 2: pasar referencia en vez de mover
fn imprimir(texto: &str) { println!("{texto}"); }
imprimir(&s);
println!("{s}");  // s sigue siendo válido
```

### `does not live long enough`

**Causa**: una referencia se usa más allá del lifetime del valor al que apunta.

```rust
// MAL
fn obtener_nombre() -> &str {  // error: falta especificador de lifetime
    let nombre = String::from("Ana");
    &nombre  // nombre se destruye al salir de la función
}

// BIEN — opción 1: retornar String (owned)
fn obtener_nombre() -> String {
    String::from("Ana")
}

// BIEN — opción 2: tomar referencia de entrada y retornarla
fn primer_nombre<'a>(texto: &'a str) -> &'a str {
    texto.split_whitespace().next().unwrap_or("")
}
```

---

## Lifetimes — Errores de Especificación

### `missing lifetime specifier`

**Causa**: el compilador no puede inferir el lifetime de una referencia en la firma.

```rust
// MAL — el compilador no sabe de dónde viene el lifetime del retorno
struct Extractor { separador: char }
impl Extractor {
    fn extraer(&self, texto: &str) -> &str {  // ambiguo: de &self o de texto?
        texto.split(self.separador).next().unwrap_or("")
    }
}

// BIEN — anotar explícitamente
impl Extractor {
    fn extraer<'a>(&self, texto: &'a str) -> &'a str {
        texto.split(self.separador).next().unwrap_or("")
    }
}
```

### `lifetime may not live long enough` en structs con referencias

```rust
// MAL
struct Reporte {
    titulo: &str,  // error: falta parametro de lifetime
}

// BIEN
struct Reporte<'a> {
    titulo: &'a str,
}
```

---

## Trait Bounds — Errores de Implementación

### `the trait X is not implemented for Y`

**Causa**: se usa un tipo donde se requiere un trait que no implementa.

```rust
// MAL
fn imprimir_todos<T>(items: Vec<T>) {
    for item in items {
        println!("{item}");  // error: T no implementa Display
    }
}

// BIEN — agregar el bound necesario
use std::fmt::Display;
fn imprimir_todos<T: Display>(items: Vec<T>) {
    for item in items {
        println!("{item}");
    }
}
```

### `cannot be sent between threads safely` / `future is not Send`

**Causa**: tipo que no implementa `Send` o `Sync` se usa en contexto async multi-hilo
(tokio, rayon).

```rust
// MAL — Rc no es Send
use std::rc::Rc;
async fn tarea() {
    let dato = Rc::new(42);
    tokio::spawn(async move { println!("{dato}"); });  // error: Rc no es Send
}

// BIEN — usar Arc para compartir entre hilos
use std::sync::Arc;
async fn tarea() {
    let dato = Arc::new(42);
    tokio::spawn(async move { println!("{dato}"); });  // ok: Arc es Send
}
```

---

## Cargo Build — Errores de Dependencias y Features

### `unresolved import` / `use of undeclared crate`

**Causa**: crate no declarado en `Cargo.toml` o feature no habilitada.

```toml
# Verificar que el crate existe en Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

# Error típico: usar serde::Serialize sin habilitar feature "derive"
# serde = "1"   <- MAL si se usa #[derive(Serialize)]
```

### `feature X is not defined in package Y`

**Causa**: se solicita un feature que no existe en esa versión del crate.

```toml
# Diagnóstico: ver features disponibles
# cargo metadata --format-version 1 | jq '.packages[] | select(.name=="nombre") | .features'

# MAL — feature inventado o renombrado en nueva version
tokio = { version = "1", features = ["io_util"] }  # nombre incorrecto

# BIEN — nombre exacto del feature
tokio = { version = "1", features = ["io-util"] }
```

---

## Clippy — Warnings que Bloquean CI

| Warning | Causa | Solución |
|---------|-------|----------|
| `needless_return` | `return expr;` al final | Quitar `return` |
| `clone_on_copy` | `.clone()` en tipo `Copy` | Quitar `.clone()` |
| `manual_map` | `match opt { Some(x) => Some(f(x)), None => None }` | Usar `opt.map(f)` |
| `unwrap_or_else` | `.unwrap_or(f())` cuando `f()` es costosa | Usar `.unwrap_or_else(\|\| f())` |
| `redundant_closure` | `\|x\| f(x)` donde `f` es una función | Usar `f` directamente |

```rust
// Suprimir warning específico documentado con razón
#[allow(clippy::too_many_arguments)]
fn configurar_pipeline(/* 8 parámetros justificados */) { }

// Para todo el proyecto en clippy.toml:
// avoid-breaking-exported-api = false
```

---

## Errores Async Avanzados

### `async fn in trait` (pre Rust 1.75)

**Causa**: versiones anteriores no soportaban `async fn` directo en traits.

```rust
// MAL en Rust < 1.75
trait Servicio {
    async fn procesar(&self) -> Result<(), Error>;  // no permitido
}

// BIEN — usar crate async-trait o boxear el futuro
use async_trait::async_trait;
#[async_trait]
trait Servicio {
    async fn procesar(&self) -> Result<(), Error>;
}

// O en Rust 1.75+ directamente sin async-trait
trait Servicio {
    fn procesar(&self) -> impl Future<Output = Result<(), Error>> + Send;
}
```

---

## Gotchas / Errores comunes no obvios

- **El compilador sugiere agregar lifetime `'a` pero agregarlo produce un error diferente en el llamador**: el error original era incorrecto en su diagnóstico — el problema real es que la función devuelve una referencia que vive menos que el caller. Causa: rustc a veces sugiere lifetimes que resuelven el error local pero desplazan el problema al sitio de llamada. Solución: en lugar de seguir la sugerencia del compilador ciegamente, dibujar el diagrama de ownership: si el valor puede no existir cuando se necesita, la solución correcta es clonar o devolver un `String`/`Vec` owned en lugar de una referencia.
- **`cannot move out of X because it is borrowed`** aparece en código que debería ser seguro: hay un `Mutex::lock()` cuyo guard no está en una variable explícita — se crea temporariamente en una expresión y se libera antes de lo esperado. Causa: `mutex.lock().unwrap().metodo()` libera el lock al final de la expresión, pero si el valor retornado tiene un lifetime ligado al lock, el compilador detecta el conflicto. Solución: asignar el guard a una variable explícita con `let guard = mutex.lock().unwrap(); let val = guard.metodo();`.
- **Clippy bloquea CI con `#[allow(clippy::X)]` que ya no es necesario en la nueva versión**: después de actualizar Rust, el `#[allow]` para un lint que ya no existe produce un warning de "unknown lint" que con `-D warnings` se convierte en error. Causa: los nombres de lints de clippy cambian entre versiones. Solución: ejecutar `cargo clippy 2>&1 | grep "unknown lint"` para detectar `#[allow]` obsoletos y eliminarlos.
- **`cargo build` falla con `error: failed to run custom build command for X-sys`**: los bindings de C a través de `*-sys` crates requieren que la librería nativa esté instalada en el sistema. Causa: crates como `openssl-sys`, `sqlite3-sys` o `libpq-sys` ejecutan un script de build que invoca `pkg-config` para encontrar la librería del sistema; si no está instalada, el build falla con un mensaje confuso. Solución: instalar la librería del sistema (`libssl-dev`, `libsqlite3-dev`, etc.) o agregar al `Cargo.toml` la feature `vendored` si el crate la ofrece (`openssl = { features = ["vendored"] }`).

## Checklist de Diagnóstico

- [ ] Leer el error completo: rustc incluye la causa, ubicación y sugerencia.
- [ ] Ejecutar `cargo check` antes de `cargo build` para feedback más rápido.
- [ ] Usar `cargo clippy -- -D warnings` en CI para detectar problemas anticipados.
- [ ] Si el error menciona lifetime: dibujar el diagrama de propiedad en papel.
- [ ] Si el error es `not Send`: buscar `Rc`, `RefCell`, `*mut`, raw pointers en el tipo.
- [ ] Si hay conflicto de features: `cargo tree -f "{p} {f}"` para ver el árbol de features.
- [ ] `RUST_BACKTRACE=1 cargo test` para stack trace completo en panics.
- [ ] `cargo expand` (requiere `cargo-expand`) para depurar macros que no compilan.
