← Blog
30 de octubre, 2026 · 7 min

x402 2.29.0: el release que cerró un mes de fixes

Los dos roundups anteriores terminaron con el mismo hallazgo: los fixes estaban en main y en ningún artefacto publicado. El 28 de octubre eso dejó de ser cierto. Esta semana trata de qué se publicó, qué rompe y qué debe hacer un gateway que fija versiones.

Buscamos PRs mergeados en x402-foundation/x402 desde el 23 de octubre 00:00 UTC hasta el 30 de octubre 12:00 UTC. La cuenta supera con mucho la ventana anterior. De esos PRs, 37 son de PhilBot402, 10 de phdargen, 9 de mintlify[bot] (docs) y 5 de lgalabru. Varios son PRs de release, así que el número bruto exagera los cambios de código. El número que importa es otro: un release.

El release, con fechas

El registro de npm fecha @x402/core 2.29.0 el 2026-10-28 18:29:54 UTC. La versión anterior, 2.28.0, es del 29 de septiembre. Son 29 días sin release mientras se mergeaban decenas de fixes.

PyPI muestra x402 2.26.0 subido a las 18:29 UTC del mismo día. La numeración de Python es independiente de npm, así que 2.26.0 en PyPI es la contraparte de 2.29.0 en npm. El módulo Go tiene un tag go/v2.29.0 y su changelog está fechado el 28 de octubre.

No nos fiamos solo del changelog. Desempaquetamos ambos tarballs. En el bundle 2.28.0 de @x402/core, el servidor HTTP no tiene fallback para HEAD ni AfterSettleAbortError. En 2.29.0 la rama HEAD está (if (!matchingRoute && upperMethod === "HEAD")) y la nueva clase de error se exporta. Para estos ítems, "mergeado" ya es "publicado".

Qué llegó a producción

Ítems que cubrimos antes como no publicados y que ahora están en los artefactos:

Novedad de esta ventana, también en 2.29.0:

// AfterSettleAbortError

Un hook puede cerrar un settle en modo fail-closed

Un hook afterSettle ahora puede lanzar AfterSettleAbortError. El settle se reporta como success: false conservando transacción, monto y payer. Los fallos de persistencia del depósito en batch-settlement EVM lo usan, así que un fallo del store ya no parece un settle exitoso. Otros errores de afterSettle siguen sin ser fatales en TypeScript. El changelog de Python declara la misma regla y anota que Go los registra en el log.

Es la misma dirección fail-closed que describimos en la auditoría de recovery: cuando el dinero ya se movió, el receipt no puede mentir sobre el ledger.

Ítems menores. Los clientes de facilitator y Bazaar ahora limitan el body bufferizado a 1 MiB en verify, settle y supported, y a 4 MiB en páginas de discovery. Un body mayor lanza ResponseBodyTooLargeError y cancela el stream. El body JSON del 402 ahora incluye el motivo del rechazo para clientes no navegador, y el catch-all de settlement de Express devuelve { "error": "settlement_failed" } en vez de {}. Los hooks afterVerify ahora corren cuando verify devuelve isValid: false. El registro de facilitator con varios namespaces conserva un wildcard por namespace CAIP-2.

Qué rompe al actualizar

Es una versión minor y trae cambios incompatibles. Léelos antes de subir la versión.

Python además acota el extra x402[mcp] a mcp<2, porque mcp 2.x eliminó mcp.server.fastmcp.

Solana: negociación de versión antes de transaction v1

Los mecanismos SVM ahora negocian la versión del mensaje de transacción. Los facilitators anuncian extra.transactionVersions en /supported, y el conjunto anunciado es [0]. Los servidores lo copian al 402. Los clientes construyen una versión anunciada o se niegan con unsupported_transaction_version. El cambio anticipa transaction v1 (SIMD-0385). El facilitator SVM upto también puede elegir la versión de las transacciones de claim, cancel y rent-cleanup que construye él mismo. En Go, sin configurar se mantiene v1.

Lo práctico: un cliente que arma pagos Solana a mano ahora tiene un campo que leer antes de firmar.

Qué significa para LLM4Agents

Nuestro gateway cotiza y liquida por llamada, así que está del lado vendedor de estos caminos de código. Tres consecuencias.

Primero, la ventana de exposición se está cerrando, no está cerrada. Todo lo que describimos durante cuatro semanas como "en main, no publicado" ahora está en una versión fijable. Cualquier despliegue que siga en 2.28.0 conserva el bypass de HEAD, el hueco del techo de override y el XSS del paywall. El código mergeado no protegió a nadie hasta el 28 de octubre.

Segundo, la actualización no es un patch bump. El cambio a zod 4 toca todo lugar que lee resultados de parseo. Un gateway que loguea ZodError.errors no registrará nada útil tras la actualización. El cambio de ID de Algorand es un rechazo duro, así que una config vieja falla en runtime, no al instalar.

Tercero, AfterSettleAbortError nos da un lugar limpio para escribir en el ledger. Si nuestro paso post-settle no puede registrar el débito, el comprador debe ver un receipt fallido, no uno exitoso que no podemos contabilizar. Aún no cambiamos nuestro código. Es el diseño que adoptaríamos, no algo que ejecutemos hoy.

Cómo mantenerse en la frontera

  1. Actualizar en una rama, no in situ. Subir @x402/core a 2.29.0 con pin, y luego buscar ZodError, .errors y cualquier string de red Algorand.
  2. Re-ejecutar las sondas de bypass. HEAD, OPTIONS y paths con %2F contra un facilitator mock. Un fix es real cuando la sonda pasa de 200 a 402 en el bundle publicado.
  3. Adoptar el hook fail-closed. Conectar nuestro registro de débito a un hook afterSettle que lance AfterSettleAbortError si el store falla.
  4. Leer transactionVersions en nuestro camino Solana y rechazar todo lo que quede fuera del conjunto anunciado.
  5. Vigilar la cadencia. Un hueco de 29 días es un riesgo. Agregar una alerta de "fix de seguridad mergeado más nuevo que el release fijado" para saber cuándo estamos expuestos.

Una salvedad de método: verificamos los tarballs y los changelogs, no el comportamiento de cada ítem. HEAD es el que reprodujimos nosotros, contra 2.28.0. El resto se apoya en el changelog y el texto de los PRs de los maintainers.

Paga por llamada, con el SDK fijado por ti

LLM4Agents sigue los releases de x402 para que tu agente no tenga que hacerlo.

Registrar agente