Cuando el arreglo correcto parece no funcionar
· Javier Miralles · 7 min
La misma semana nos pasó dos veces, en dos sitios que no tienen nada que ver: arreglamos lo que estaba mal, comprobamos que el cambio era correcto, y el síntoma seguía exactamente igual. La tentación en ese momento es clarísima y casi siempre errónea: desconfiar del arreglo y ponerse a tocar otra cosa. En los dos casos el arreglo estaba bien. Lo que fallaba es que una segunda capa —una variable de entorno en un servidor, un flag de rutas en una VPN— tapaba el efecto en silencio, y el síntoma seguía apuntando al culpable equivocado. Este es el postmortem de los dos, con los valores exactos, y por qué el error de método es siempre el mismo.
Contexto: dos incidentes, un mismo patrón
El 7 de julio de 2026 tuvimos dos fuegos. Uno en el App Store de Shopify: EasyBadge, la segunda app que llevamos a revisión, volvió a ser rechazada, esta vez por la parte de cobros. Otro en nuestra propia infraestructura: el servidor que corre a Atlas, el sistema de automatización interno del estudio, se quedó sin conexión a la red privada de madrugada y las rutinas dejaron de funcionar.
Los dos incidentes son de dominios distintos —uno es un frontend embebido en Shopify, el otro es red y VPN— y a primera vista no comparten nada. Comparten la trampa: en ambos hicimos el cambio correcto, lo verificamos a nivel de código o de comando, y el sistema siguió comportándose como si no hubiéramos tocado nada. Esa desconexión entre "el cambio es correcto" y "el síntoma no se mueve" es la que hace perder horas, porque empuja a arreglar cosas que nunca estuvieron rotas.
El problema: el arreglo estaba bien, la capa de encima lo comía
Caso uno: una variable de entorno que gana al código
Shopify rechazó EasyBadge por el requisito 1.2.2, el de precios gestionados. El texto del revisor era preciso: "la app redirige al índice de aplicaciones al intentar comprar el plan de suscripción". Traducido: cuando el comerciante pulsa "mejorar a Pro", en lugar de abrirse la ventana de planes, Shopify lo devuelve a la lista de apps del panel. El cobro nunca arranca.
El botón construye la URL de la página de planes así:
admin.shopify.com/store/<tienda>/charges/<handle>/pricing_plans
donde <handle> sale de process.env.SHOPIFY_APP_HANDLE || "easybadge". Nuestro primer instinto fue el mecanismo del botón: quizá el fetcher de Remix no navegaba bien dentro del iframe embebido. Así que lo cambiamos por un Form, luego por un window.open con App Bridge v4, y de paso corregimos el valor por defecto del código (estaba en easybadge-1, lo dejamos en easybadge). Desplegamos. El botón seguía devolviendo a la lista de apps. Idéntico.
La causa real estaba en un sitio que no habíamos mirado: el .env.production del servidor tenía SHOPIFY_APP_HANDLE=easybadge-2. Ese easybadge-2 es una etiqueta de versión que deja la CLI de Shopify, no un handle real del App Store. Y aquí está el detalle que lo explica todo: la variable de entorno gana al valor por defecto del código. Da igual lo que pusiéramos en el || "easybadge": mientras el entorno dijera easybadge-2, la URL apuntaba a una página de planes que no existe, y Shopify, ante una página de planes inexistente, hace lo que hace siempre: te devuelve a la lista de apps.
El síntoma "redirige a la lista de apps" fue siempre el handle equivocado. Nunca fue el mecanismo del botón. Cambiar el fetcher por Form, el Form por window.open, el easybadge-1 por easybadge: cada uno de esos cambios era una mejora legítima y ninguno tocaba la causa, porque la causa vivía en una variable de entorno que sobrescribía el código antes de que el código tuviera nada que decir.
El arreglo de verdad fue de una línea, un sed sobre el fichero de entorno, easybadge-2 → easybadge, y recrear el contenedor para que releyera el env_file:
docker compose up -d --force-recreate
docker exec eb-badges printenv SHOPIFY_APP_HANDLE # → easybadge
Ese printenv es la parte que faltaba las horas anteriores: comprobar el valor en el sitio que decide, dentro del contenedor en marcha, no en el código del repo. Con el handle correcto, el clic de "mejorar a Pro" abrió por fin la ventana con los planes Free y Pro (4,99 $). Reenviamos las correcciones a revisión.
Caso dos: una sesión que caduca y un flag que se reinicia
El mismo día, más temprano, el servidor de Atlas se quedó incomunicado. La red privada del estudio la gobierna headscale (un coordinador de VPN autoalojado, del ecosistema Tailscale), y headscale pone caducidad de 24 horas a cada registro por OIDC. La sesión del servidor expiró de madrugada, la resolución de nombres internos dejó de funcionar y con ella el acceso a Forgejo y a Odoo. Sin eso, las rutinas de Atlas se bloquean enteras.
El arreglo evidente: volver a registrar el servidor. Hecho el re-login por OIDC, la sesión quedó activa. Y sin embargo la conexión a los servicios internos seguía sin ir. Otra vez el mismo cuadro: el arreglo era correcto —la sesión estaba de nuevo viva—, el síntoma no se movía.
La segunda capa aquí fue un flag: tras el re-registro, el nodo quedó con RouteAll: false. Es decir, la sesión estaba bien, pero el cliente había dejado de aceptar las rutas de subred (las 10.1.x internas), así que los nombres internos seguían sin resolver. El fallo estaba escondido detrás de un arreglo que sí había funcionado. Un tailscale set --accept-routes lo cerró.
Lo que salió bien y lo que dolió
Lo que salió bien es que en los dos casos, una vez identificada la segunda capa, el arreglo real fue trivial: una línea de sed, un flag de rutas. Los problemas de este tipo son baratos de arreglar y carísimos de encontrar.
Lo que dolió es cuánto tardamos en dejar de tocar la capa equivocada. En el caso de Shopify cambiamos el mecanismo del botón tres veces —cada cambio con su despliegue, su espera, su nueva comprobación— antes de ir a mirar la variable de entorno del servidor. Todo ese rato estuvimos "arreglando" algo que no estaba roto, convencidos de que como el síntoma no cambiaba, nuestro último cambio tampoco había servido. Y sí servía: lo que pasaba es que otra cosa lo tapaba. Es un bucle que se retroalimenta: el arreglo correcto, al no mover el síntoma, parece un arreglo fallido, y eso te empuja a descartarlo y probar otra cosa, alejándote de la causa justo cuando ya la tenías cercada.
La lección incómoda es de método, no de conocimiento. No nos faltaba saber cómo funciona una variable de entorno o un flag de rutas. Nos faltó, en caliente, la disciplina de verificar que el arreglo había aterrizado en la capa que realmente decide antes de concluir que no servía.
Lecciones para quien esté peleando con un síntoma que no se mueve
- Si el arreglo es correcto y el síntoma no cambia, no descartes el arreglo: busca la capa que lo tapa. El instinto de "esto no ha funcionado, pruebo otra cosa" es exactamente lo que te aleja de la causa cuando ya la tenías.
- La configuración gana al código. Una variable de entorno, un flag, un valor en un fichero de despliegue sobrescriben en silencio lo que pusiste en el fuente. Antes de tocar el código, comprueba qué valor está vivo de verdad.
- Verifica en el sitio que decide, no donde te resulta cómodo.
printenvdentro del contenedor en marcha,tailscale statusen el nodo real. El valor del repo o el comando que creíste haber lanzado no cuentan: cuenta el estado del proceso que atiende la petición. - Un síntoma constante ante cambios distintos apunta a una causa que ninguno toca. Si cambias el mecanismo tres veces y el fallo es idéntico las tres, el mecanismo no es el problema. Deja de iterar sobre él.
- Después de un re-login o un redespliegue, revisa los efectos secundarios. Reautenticar puede resetear rutas; recrear un contenedor puede recargar —o no— el entorno. El paso "arreglar" tiene su propia letra pequeña.
Construir el arreglo, en los dos casos, fue un minuto. Encontrar dónde iba fue la tarde entera. Y esa asimetría es justo el oficio: la parte cara nunca es escribir la línea correcta, es saber en qué capa ponerla.
Si estás dando vueltas a un bug que no se mueva por más que lo arregles, y sospechas que algo tapa tu cambio pero no sabes dónde mirar, escríbenos a contact@easybyte.es. Te contamos por dónde empezaríamos a levantar capas. Nosotros perdimos una semana con dos de estas: puedes ahorrarte al menos una.
— Javier
EasyByte Hub S. Coop. Mad. — Madrid, julio de 2026