7 gotchas de cron que rompen tus tareas sin avisar
Los errores silenciosos en expresiones cron son los peores: tu tarea no se ejecuta, no hay mensaje de error, no hay alerta, y el problema puede pasar días sin que nadie lo note. Un backup que nunca se hizo, un reporte que nunca se mandó, una tarea de limpieza que dejó el servidor lleno. Todo eso por una expresión mal escrita que el sistema aceptó sin chistar.
En 30 segundos
6 * * * *no significa “cada 6 horas” sino “a las 6:00 AM”. Para cada 6 horas necesitás*/6 * * * *.- GitHub Actions ejecuta cron en UTC, no en tu zona horaria. Para Argentina (UTC-3), si querés las 9 AM local tenés que escribir
0 12 * * *. - AWS EventBridge rechaza
*/6con un error genérico de validación, sin decirte qué está mal exactamente. - En Linux, especificar día del mes Y día de la semana usa lógica OR. En AWS/Quartz, uno de los dos campos tiene que ser
?. - Cron no carga tu
.bashrcni.profile, así que comandos comopythononodefallan si no usás la ruta absoluta.
Cloudflare es una plataforma de seguridad y rendimiento en la nube fundada en 2010 por Matthew Price, Lee Holloway y Michelle Zatlyn. Proporciona servicios de CDN, protección DDoS, gestión de DNS y aceleración web.
Una expresión cron es una cadena de cinco (o seis, dependiendo de la plataforma) campos separados por espacios que define cuándo ejecutar una tarea: minuto, hora, día del mes, mes, y día de la semana. Simple en teoría. En la práctica, hay al menos siete formas comunes de arruinarla sin que el sistema te avise.
Error 1: Confundir “cada N horas” con “a las N:00”
Este es el más clásico y el que más veces he visto en pull requests. Alguien escribe:
6 * * * *— creyendo que significa “cada 6 horas”- Lo que realmente hace: ejecutar a las 6:00 AM todos los días
Para ejecutar cada 6 horas, la expresión correcta es */6 * * * *. La barra inclinada indica “cada N unidades”. Sin la barra, estás seleccionando un valor fijo, no un intervalo.
Lo mismo aplica a minutos: 30 * * * * ejecuta al minuto 30 de cada hora. */30 * * * * ejecuta cada 30 minutos. La diferencia parece obvia cuando la ves así, pero bajo presión y a las 2 AM no tanto.
Error 2: Ignorar la zona horaria (GitHub Actions vive en UTC)
Ponele que configurás un workflow en GitHub Actions para que corra a las 9 AM todos los días. Escribís:
0 9 * * *
¿Y qué pasa? Se ejecuta a las 9:00 UTC. Si estás en Argentina (UTC-3), eso es las 6:00 AM. Si tu equipo está en España (UTC+2 en verano), son las 11:00 AM. GitHub Actions no tiene soporte nativo de zonas horarias en cron: todo corre en UTC, sin excepciones.
Hay otro problema encima de ese: bajo carga alta, GitHub Actions puede demorar entre 5 y 30 minutos en arrancar un job programado. Un job configurado para las 9:00 UTC puede dispararse a las 9:22. Si tenés dependencias downstream que esperan que el job termine antes de cierta hora, eso puede romper la cadena completa (sin ningún error visible, claro).
La solución es siempre calcular la hora en UTC. Para las 9 AM en Argentina: 0 12 * * *.
Error 3: Sintaxis que plataformas rechazan sin decirte por qué
AWS EventBridge tiene su propia sintaxis de cron, y hay diferencias importantes con el estándar de Linux. Por ejemplo, */6 en el campo de horas no funciona en EventBridge. Si intentás usarlo, recibís un error genérico de validación que no especifica qué campo está mal ni qué sintaxis espera.
Según la documentación de AWS, EventBridge requiere usar 0/6 en lugar de */6, y además agrega un sexto campo para el año. La misma expresión que funciona perfectamente en tu servidor Linux va a fallar en EventBridge sin que el mensaje de error te oriente.
Vercel, Azure Functions y Google Cloud Scheduler también tienen sus particularidades. Antes de asumir que la sintaxis es portable, revisá la documentación específica de cada plataforma.
Error 4: El comportamiento OR/AND entre día del mes y día de la semana
¿Querés ejecutar algo el primer lunes de cada mes? Intuitivamente escribís:
0 0 1 * 1
¿Y qué hace en Linux? Ejecuta el día 1 de cada mes, más cada lunes del año. Eso es lógica OR: si se cumple cualquiera de las dos condiciones, corre. No es lo que querías. Relacionado: plataformas de CI/CD con scheduling.
¿Y en AWS EventBridge? No te deja especificar los dos campos al mismo tiempo. Uno de los dos tiene que ser ? (valor indiferente). Si ponés ambos con valores concretos, error de validación.
Para lograr “el primer lunes de cada mes” en Linux, necesitás un guard en el script:
0 0 * * 1 [ $(date +\%d) -le 07 ] && /ruta/script.sh
Sí, es feo. Pero es la única forma de hacerlo correctamente en cron estándar.
Error 5: No considerar las limitaciones del plan o plataforma
Vercel Hobby permite exactamente un cron job por día. Si configurás 0 * * * * (cada hora) en un proyecto con Hobby plan, Vercel lo acepta al momento de hacer el deploy, pero en la práctica solo lo ejecuta una vez al día. Sin error, sin warning, sin notificación.
Otras restricciones comunes que se descubren de la peor manera:
- Cloudflare Workers: frecuencia mínima de 1 minuto, timeout de 30 segundos por ejecución
- Railway: en planes gratuitos, los cron jobs se pausan después de inactividad
- Render: el plan gratuito suspende servicios después de 15 minutos sin tráfico HTTP, lo que afecta la confiabilidad de los cron jobs
Antes de configurar cualquier cron job en una plataforma nueva, revisá las limitaciones del plan activo. No des por supuesto que lo que ves en el dashboard es lo que realmente va a pasar.
Error 6: Variables de entorno y PATH incompleto
Cron no carga tu .bashrc, tu .bash_profile ni nada que hayas configurado en tu sesión interactiva. El PATH que tiene disponible es mínimo: típicamente /usr/bin:/bin y nada más.
Lo que pasa entonces: escribís un cron job que llama a python script.py, lo probás en tu terminal y funciona. Cron lo ejecuta y falla silenciosamente porque python no está en /usr/bin, está en /usr/local/bin/python3 o en un virtualenv que nunca se activó.
La solución es siempre usar rutas absolutas:
- MAL:
* * * * * python /home/user/script.py - BIEN:
* * * * * /usr/local/bin/python3 /home/user/script.py
Si usás un virtualenv, tenés que activarlo explícitamente: * * * * * /home/user/venv/bin/python /home/user/script.py.
Para debuguear el PATH que tiene cron disponible, podés agregar temporalmente: * * * * * env > /tmp/cron_env.txt y revisar ese archivo.
Error 7: No capturar el output — la fuente de todos los errores silenciosos
Por defecto, cron envía el output por correo al usuario del sistema. Si el servidor no tiene un agente de correo configurado (la mayoría no lo tiene), ese output desaparece para siempre.
¿El resultado? Tu script falla, cron no ejecuta nada, y vos no te enterás hasta que alguien pregunta por qué no llegó el reporte del mes.
La forma mínima de evitarlo:
0 2 * * * /ruta/script.sh >> /var/log/cron-script.log 2>&1
El 2>&1 redirige stderr al mismo archivo que stdout. Sin eso, los errores del script van a un lugar diferente (o a ningún lado). Con eso, tenés un log que podés revisar con grep -i error /var/log/cron-script.log o monitorear con cualquier herramienta de logs. Para más detalles técnicos, mirá ejecutar agentes automáticamente.
¿Y si el log crece demasiado? Configurá logrotate o usá tee -a con algún límite. Pero siempre, siempre capturá el output.
Comparativa: sintaxis cron por plataforma
| Plataforma | Campos | Soporta */N | Zona horaria | Observaciones |
|---|---|---|---|---|
| Linux/crontab | 5 | Sí | Sistema / por usuario | Referencia estándar |
| GitHub Actions | 5 | Sí | UTC fija | Delays de 5-30 min bajo carga |
| AWS EventBridge | 6 (+ año) | No, usar 0/N | UTC fija | Requiere ? en día-mes o día-semana |
| Vercel | 5 | Sí | UTC fija | Hobby: 1 job/día máximo |
| Cloudflare Workers | 5 | Sí | UTC fija | Mínimo 1 minuto, timeout 30 seg |
| Google Cloud Scheduler | 5 | Sí | Configurable | Una de las pocas que permite TZ custom |

Qué significa esto para equipos en Argentina y Latinoamérica
El problema de UTC es especialmente relevante acá. Con Argentina en UTC-3 (y sin observar horario de verano), cualquier plataforma que fije la zona a UTC requiere que el equipo haga la conversión manualmente. Y si trabajás con personas en distintos países del continente, la cosa se complica: Colombia y Perú están en UTC-5, Chile en UTC-4, México central en UTC-6.
El tip práctico: documentá siempre los cron jobs con la hora UTC explícita en un comentario, no con la hora local. Si estás buscando un hosting con infraestructura confiable para correr servicios con cron jobs críticos, donweb.com tiene servidores VPS donde vos configurás la zona horaria del sistema sin depender de restricciones de plataforma.
Errores comunes al diagnosticar cron jobs rotos
Probar la expresión solo en crontab.guru y dar por buena. Esa herramienta valida sintaxis estándar de Linux. No te dice si funciona en AWS EventBridge, Vercel o GitHub Actions. Cada plataforma tiene que validarse en su propia documentación.
Asumir que “no hubo error” significa “corrió bien”. Sin captura de output, el silencio no es éxito. Es ausencia de información. Un script que falla en la línea 3 y uno que completa sin problemas se ven exactamente igual si no hay logs.
Debuguear el script en la terminal y darlo por resuelto. Si el problema es el PATH o las variables de entorno, el script va a funcionar perfecto en tu terminal y fallar igual en cron. Siempre probá con el entorno más restrictivo posible: sin cargar tu profile, con el PATH mínimo.
Preguntas Frecuentes
¿Cuál es la diferencia entre */6 y 6 en una expresión cron?
*/6 en el campo de horas significa “ejecutar cada 6 horas” (a las 0:00, 6:00, 12:00 y 18:00). El número 6 sin barra significa “ejecutar a las 6:00 AM”. La barra inclinada indica un paso o intervalo, no un valor fijo. Es la diferencia entre correr 4 veces al día o una sola vez.
¿Por qué mi cron job se ejecuta a la hora equivocada?
Lo más común es un problema de zona horaria. Plataformas como GitHub Actions, AWS EventBridge y Vercel usan UTC fijo. Si configuraste la hora en tu zona horaria local y no convertiste a UTC, el job corre con la diferencia horaria de error. Para Argentina (UTC-3), sumá 3 horas a la hora local para obtener la hora UTC correcta.
¿Cómo verificar si un cron job tiene errores silenciosos?
Redirigí stdout y stderr a un archivo de log: tu_comando >> /var/log/cron.log 2>&1. Sin ese redireccionamiento, los errores desaparecen si el servidor no tiene configurado un agente de correo. Después podés revisar el log con grep -i error /var/log/cron.log o configurar una alerta si el archivo crece más de lo esperado.
¿Qué diferencia hay entre día del mes y día de la semana en cron?
En Linux crontab estándar, si especificás ambos campos con valores (por ejemplo día 15 y lunes), el job corre cuando se cumple cualquiera de los dos: el día 15 de cada mes o cualquier lunes. Es lógica OR, no AND. En AWS EventBridge, tenés que poner ? en uno de los dos campos; no te permite especificar ambos simultáneamente.
¿Cómo evitar errores silenciosos en expresiones cron?
Tres cosas básicas: capturá el output con 2>&1 >> log.txt, usá rutas absolutas para todos los comandos (no dependas del PATH de tu sesión), y validá la expresión en la plataforma específica donde va a correr, no solo en un validador genérico. Para plataformas cloud, revisá también los límites del plan antes de asumir que la frecuencia configurada se va a respetar.
Conclusión
Los errores silenciosos en expresiones cron no son bugs oscuros de casos extremos. Son trampas que aparecen en el día a día de cualquier equipo que automatiza tareas: la diferencia entre 6 y */6, las zonas horarias fijas en UTC, el PATH recortado que rompe comandos que funcionan perfecto en la terminal. El artículo original que motivó esta nota documenta casos reales, incluyendo uno que costó un día entero de backups perdidos.
La solución no es compleja. Capturá el output siempre. Convertí a UTC cuando la plataforma lo requiera. Usá rutas absolutas. Y antes de dar por buena una expresión, revisá la documentación específica de la plataforma donde va a correr, porque lo que funciona en Linux puede fallar silenciosamente en AWS o Vercel sin un mensaje de error útil.






