PyPI explica los errores 502 de agosto: qué falló en Fastly

Qué pasó realmente en PyPI entre el 15 y el 28 de agosto

Durante dos semanas de agosto de 2026, miles de developers que corrieron pip install empezaron a ver errores 502 y 503 intermitentes al descargar paquetes desde files.pythonhosted.org. No fue un único corte limpio: el síntoma llegó en oleadas, con paquetes rotos a mitad de instalación y pipelines de CI fallando sin razón aparente.

Según el postmortem oficial publicado en el PyPI Blog, dos problemas distintos se combinaron para producir el ruido de errores:

  • Un canary deployment dentro de la red de Fastly dejó la configuración de cache desincronizada del routing en un punto de presencia (POP) del área de Seattle. El routing siguió mandando tráfico a esa POP mientras la config de cache estaba revertida, así que el edge respondía 502 para cualquier request que cayera ahí.
  • Varios bugs en la propia configuración de PyPI en Fastly, heredados de hacía tiempo, que solo se hicieron visibles cuando el equipo se puso a investigar los reportes. Uno impedía caer al backend de S3 cuando B2 no respondía (timeout, TLS fail); otro afectaba a los range requests que los installers usan para leer .whl.metadata sin bajarse el wheel entero; un tercero afectaba a una exención de segmented caching que se evaluaba antes de normalizar la URL, así que un ?token=x en la query string la rompía y dejaba una respuesta 501 cacheada para todos los requests siguientes.

El resultado: el 15 de agosto empezó el ruido, el 17 se abrieron los primeros issues en el tracker de soporte de PyPI, el 18 se confirmó que eran 502 reales y no algo en el lado del usuario, y el 28 de agosto Fastly parcheó el canary defectuoso y sacó todo el tráfico de la PSF —incluido PyPI— de su cohorte de canary. Desde entonces, los downloads volvieron a funcionar con normalidad.

👥 ¿Quieres ir más allá de la noticia?

En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.

👥 Unirme a la comunidad

La arquitectura que dejó al descubierto el fallo

PyPI no sirve archivos desde un único servidor: files.pythonhosted.org es un servicio CDN de Fastly delante de tres backends:

  • Backblaze B2: el primario. Hay un acuerdo de egress gratis entre Fastly y Backblaze, así que servir archivos desde B2 a través de Fastly solo cuesta el storage. Por eso PyPI sincroniza cada archivo nuevo ahí.
  • Amazon S3: el origen durable donde se escribe primero al subir el paquete. PyPI usa la clase S3 Glacier Instant Retrieval para balancear storage y retrieval cost. Funciona como fallback cuando B2 falla, pero es más caro.
  • Conveyor: un tercer backend que maneja todo lo que no es un archivo de paquete — URLs predecibles, redirects legacy, etc.

El flujo normal es: Fastly pide a B2, recibe el archivo, lo cachea con Cache-Control: max-age=365000000, immutable, public —unos 11,5 años— y sirve desde caché. El problema llegó cuando ese edge no siempre notaba que B2 había fallado, así que en vez de caer a S3 sintetizaba su propio 503.

Cómo se resolvió: la cronología completa

El postmortem trae un timeline día por día que vale la pena recorrer porque es un caso real de debugging distribuido:

  • 15 de agosto: Fastly reporta que el problema arranca en un único cache node del área de Seattle, corroborado por el issue #11876.
  • 17 de agosto: se abren los primeros dos issues persistentes de 502 en files.pythonhosted.org, el #11895 y el #11897.
  • 18 de agosto: el #11908 aporta una reproducción detallada: 88 errores 502 en seis horas, distribuidos en 32 paquetes sin relación entre sí, incluyendo los range requests de .whl.metadata que usan los installers para leer PEP 658 metadata sin descargar todo el wheel. Ese mismo día mergea infra#237, arreglando el failover de B2 al archivo S3 cuando B2 no responde (no cuando responde con error).
  • 19 de agosto: el #11925 aísla el problema en un único cache node, cache-pae2080020: 502 en cada request ruteada a ese nodo durante más de 19 horas, confirmado por los headers x-served-by. Fastly quita un override de routing que mandaba tráfico a ese POP. Mergearon también infra#238 (logging) y infra#239 (rechazo de métodos HTTP sin sentido en un file host).
  • 20 de agosto: Fastly observa recuperación en el POP afectado y confirma que la tasa elevada de errores paró.
  • 21 de agosto: mergea infra#241, exentando los suffix range requests y multi-range del segmented caching, después de que un único cliente mandara ranges lógicamente inválidos y generara un spike matutino.
  • 24 de agosto: mergea infra#243, después de que dos downloaders paralelos rotos generaran 41.315 errores más de la misma clase en un solo día.
  • 28 de agosto: Fastly parchea el bug subyacente en su canary y saca todo el tráfico de la PSF —PyPI incluido— de la cohorte. Mergea infra#245, que arregla un bug de URL normalization ordering que dejaba una respuesta mala cacheada y servida a todos los requests siguientes.

El factor humano: por qué estos bugs llevaban tiempo ahí

El post reconoce algo incómodo: estos bugs no eran nuevos. Estaban en la configuración desde hacía tiempo y nadie los había visto porque no había tráfico suficiente con los patrones correctos para dispararlos. La métrica de Datadog muestra que la línea base de errores 5xx ya estaba ruidosa antes del incidente —de miles a decenas de miles por día— y eso hizo que el aumento del 15 de agosto pasara desapercibido. El spike del 21 de agosto, en cambio, fue el que no se pudo ignorar: un único cliente enviando ranges inválidos empujó el conteo cerca del millón de errores.

Después del merge de infra#241, el tráfico se quedó dos a tres órdenes de magnitud por debajo de la línea base previa al incidente. Como dice el post: parte de lo que se venía tratando como ruido de fondo era este bug corriendo todo el tiempo.

Un punto técnico interesante: el segmented caching de Fastly no soporta suffix ranges (bytes=-1024, los últimos N bytes) ni ranges cuyo inicio está más allá del final del archivo. Devuelve un 501 sintético, que es la clase de status equivocada para un request de cliente malformado. El equipo de PyPI abrió un ticket con Fastly para arreglar eso del lado del CDN; mientras tanto, su código de manejo ya está en producción.

Qué significa esto para tu startup

PyPI es infraestructura crítica para prácticamente cualquier empresa de software, pero la mayoría de founders lo trata como un detalle del runtime hasta que algo se rompe. Este incidente deja tres lecciones accionables:

  • Cachea las dependencias de CI en el runner, no en PyPI. Una parte enorme del tráfico que golpea files.pythonhosted.org son jobs de CI instalando las mismas dependencias que ya instalaron en el run anterior, y buena parte de eso viene de GitHub Actions. Cachear dependencies no solo te protege cuando PyPI o Fastly tienen un mal día: hace tus builds más rápidos y baratos.
  • setup-python con pip, pipenv y poetry trae cacheo opt-in vía el input cache, off by default.
  • setup-uv lo trae on by default en la mayoría de eventos de GitHub-hosted runners, pero conviene verificarlo en tu workflow.
  • Un dependency cacheado que no cambia no toca PyPI en el siguiente run.
  • Diseña para que tu stack degrade con fallos intermitentes. Si tu install de pip falla a mitad con un 502, ¿tu CI reintenta? ¿Tu build de producción asume que las dependencias son inmutables y falla limpio si no las puede obtener? Vale la pena tener una estrategia explícita de reintentos y de pinning (hashes, no solo versiones) para que un día malo del CDN no se traduzca en un deploy roto.
  • Invierte en observabilidad de terceros, no solo de tu código. El equipo de PyPI detectó el problema porque usuarios del soporte reportaron headers x-served-by y timestamps. Si dependes de un proveedor externo (CDN, API, registry), instrumenta al menos logs y alertas básicas de disponibilidad y latencia de ese proveedor —es la diferencia entre enterarte por un tweet o por un postmortem que escribes tú.

El post cierra con dos anuncios que vale la pena seguir: la Python Software Foundation está contratando un infrastructure engineer para sumarse al equipo de cuatro que mantiene PyPI, y el rol está patrocinado por Alpha-Omega.

Fuentes

¿te gustó o sirvió lo que leíste?, Por favor, comparte.

👥 ¿Quieres ir más allá de la noticia?

En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.

👥 Unirme a la comunidad

Daily Shot: Tu ventaja táctica

Lo que pasó en las últimas 24 horas, resumido para que tú no tengas que filtrarlo.

Suscríbete para recibir cada mañana la curaduría definitiva del ecosistema startup e inversionista. Sin ruido ni rodeos, solo la información estratégica que necesitas para avanzar:

  • Venture Capital & Inversiones: Rondas, fondos y movimientos de capital.
  • IA & Tecnología: Tendencias, Web3 y herramientas de automatización.
  • Modelos de Negocio: Actualidad en SaaS, Fintech y Cripto.
  • Propósito: Erradicar el estancamiento informativo dándote claridad desde tu primer café.

📡 El Daily Shot Startupero

Noticias del ecosistema startup en 2 minutos. Gratis, todos los días.

Share to...