Errores comunes en recursión y cómo evitarlos (guía práctica para programadores)
La recursión es una de esas herramientas que, cuando la entiendes, te abre puertas: recorrer árboles, trabajar con grafos, resolver problemas de divide y vencerás, generar combinaciones, procesar estructuras anidadas, y mucho más.
La recursión es una de esas herramientas que, cuando la entiendes, te abre puertas: recorrer árboles, trabajar con grafos, resolver problemas de divide y vencerás, generar combinaciones, procesar estructuras anidadas, y mucho más. Pero también es una fuente clásica de bugs: funciones que nunca terminan, resultados incorrectos “por un detalle”, o programas que se caen con un stack overflow (desbordamiento de pila).
Este artículo reúne los errores comunes en recursión y, sobre todo, cómo evitarlos con un enfoque simple: terminación, corrección y eficiencia.
1) No definir (o definir mal) el caso base
El caso base es la condición que le dice a tu función: “hasta aquí llegamos, devuelve un resultado”. Sin caso base, la recursión se convierte en una espiral infinita. Y con un caso base incorrecto, puede terminar “a tiempo” pero devolviendo resultados mal.
Señales de este error
Tu función se llama a sí misma “para siempre”.
El programa se congela o termina con stack overflow.
Para entradas pequeñas funciona, pero para otras falla.
Cómo evitarlo
Antes de escribir la recursión, escribe el caso base en una frase:
“Si el problema es lo suficientemente pequeño, sé la respuesta inmediatamente”.
Usa el test mental: ¿cuál es la entrada mínima válida? Ese suele ser tu caso base.
Si hay más de un escenario de salida (por ejemplo: listas vacías y listas de un elemento), define más de un caso base.
2) El paso recursivo no se acerca al caso base
Este es el “primo” del error anterior: sí existe caso base, pero tu función no avanza hacia él. Cambias el parámetro equivocado, o lo cambias en la dirección incorrecta.
Ejemplo típico (conceptual)
Quieres reducir
nen cada llamada… pero lo aumentas.Quieres recortar una lista… pero pasas la misma lista intacta.
Cómo evitarlo
Define un “medidor de progreso”: algo que decrece o se simplifica en cada llamada (tamaño de lista, valor de n, altura restante del árbol, índice que avanza).
Pregunta clave: ¿qué variable está garantizado que cambia en cada llamada?
Si no puedes responder eso, tu recursión está incompleta.
3) Caso base correcto, pero retorno incorrecto (olvidar devolver)
Muchos errores en recursión no son de terminación, sino de retorno. La función llega al caso base, pero el valor no se propaga hacia arriba correctamente.
Señales de este error
Te devuelve
null,undefinedo cero cuando esperabas algo.Hace “algo”, pero no lo acumula.
La salida está incompleta.
Cómo evitarlo
Piensa en recursión como “capas” que se apilan. Cada capa debe:
hacer su parte
combinarla con el resultado de la llamada recursiva
devolver el resultado combinado
Si la función debe producir un valor, asegúrate de que todas las ramas (caso base y caso recursivo) devuelvan algo.
4) Confundir “trabajar antes” vs “trabajar después” de la llamada recursiva
En recursión, el orden importa: puedes hacer trabajo antes de llamar (preorden), entre llamadas (inorden) o después (postorden). Cambiar el orden cambia el resultado.
Ejemplos donde esto rompe todo
Recorrer un árbol y esperas un orden específico.
Construir una lista de salida en el orden correcto.
Imprimir o acumular resultados.
Cómo evitarlo
Decide el orden con intención:
Antes: cuando necesitas preparar/validar/registrar antes de profundizar.
Después: cuando necesitas el resultado “resuelto” de niveles más profundos para combinar.
Si el resultado sale “al revés”, revisa dónde estás acumulando/concatenando.
5) Repetir subproblemas (explosión de tiempo)
Este es el gran problema de recursión “naive”: la función resuelve lo mismo muchas veces. Pasa mucho con Fibonacci, conteo de caminos, combinaciones, etc. El resultado: complejidad exponencial.
Señales
Para entradas medianas, tarda una eternidad.
El CPU se dispara.
Muchas llamadas repetidas con los mismos parámetros.
Cómo evitarlo
Memoización: guarda resultados de subproblemas ya resueltos.
O cambia el enfoque a programación dinámica (tabulación).
Regla práctica: si tu recursión hace más de una llamada recursiva por nivel (por ejemplo, dos o más ramas), sospecha de repetición.
6) Stack overflow / límite de profundidad
Aunque tu lógica sea correcta, algunos lenguajes tienen límites de recursión relativamente bajos. Si trabajas con listas grandes, recursión profunda puede romper.
Señales
Funciona con inputs pequeños, falla con grandes.
Error explícito de “maximum call stack size” o “recursion depth exceeded”.
Cómo evitarlo
Si el problema puede resolverse iterativamente, considera un loop.
Usa una pila explícita (estructura stack) para simular recursión en casos de profundidad muy grande.
Reduce profundidad: divide el problema de forma más balanceada si es posible (por ejemplo, divide y vencerás bien aplicado).
7) Variables globales o estado compartido que se contamina
A veces la recursión parece fallar, pero el verdadero problema es que estás usando una variable global (o mutable) para acumular resultados, y esa variable se modifica en múltiples caminos.
Señales
Resultados duplicados o faltantes.
Comportamiento distinto entre ejecuciones.
Errores raros en recursión con backtracking (combinaciones, laberintos).
Cómo evitarlo
Prefiere devolver resultados en vez de depender de estado global.
Si usas acumuladores, pásalos como parámetro (y entiende si se comparte o se copia).
En backtracking, aplica la regla: “hago cambios → llamo → deshago cambios”.
8) Condiciones mal puestas en ramas múltiples
En recursión con condicionales (if/else) es fácil dejar una rama sin caso base o con un paso recursivo incorrecto.
Cómo evitarlo
Revisa que cada rama cumpla:
termina o
avanza hacia el caso base
Haz pruebas con entradas que fuerzan cada rama.
9) Off-by-one y límites en índices
En recursión con arrays, índices y rangos (inicio/fin), los errores de “+1” o “-1” son muy comunes.
Señales
Falla solo en el primer/último elemento.
Devuelve resultados casi correctos.
Cómo evitarlo
Define claramente el contrato:
¿tu rango es inclusivo o exclusivo?
¿tu caso base es “inicio > fin” o “inicio == fin”?
Escribe en comentario la regla del rango antes de programar.
10) Usar recursión cuando una iteración es más clara (y más segura)
La recursión es elegante, pero no siempre es la mejor opción. Si el problema es lineal y la recursión solo complica, puedes terminar con bugs evitables.
Cómo decidir
Usa recursión cuando:
la estructura es naturalmente recursiva (árboles, estructuras anidadas)
la solución se expresa claramente como “problema + subproblema”
Usa iteración cuando:
la profundidad puede ser enorme
la lógica queda más simple con un loop