Error SQL con `screened_ip_addresses` (la API devuelve 500)

Hola amigos,

La API me está devolviendo un error 500 cuando llamo para crear una nueva publicación (en un tema existente). En los registros veo:

ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERROR:  sintaxis de entrada no válida para el tipo inet: ""
LINE 1: ..._addresses".* FROM "screened_ip_addresses" WHERE ('' <<= ip_...
                                                             ^
)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-2.0.1/lib/patches/db/pg.rb:69:in `exec_params'

No se pudo manejar la excepción en el middleware de la aplicación de excepciones: PG::InvalidTextRepresentation: ERROR:  sintaxis de entrada no válida para el tipo inet: ""
LINE 1: ..._addresses".* FROM "screened_ip_addresses" WHERE ('' <<= ip_...
                                                             ^

Aquí está mi lista de IPs filtradas: además de la captura de pantalla a continuación, también he puesto en la lista blanca la IP de la máquina que está llamando a la API. (Estoy usando una clave de API a nivel de sistema para importar masivamente temas/mensajes antiguos desde mi antiguo software de foro.)

Solo por probar, también le pedí a la API la lista de IPs filtradas… mismos resultados. (https://mydiscourse.com/admin/logs/screened_ip_addresses.json)

No estoy seguro de qué más verificar. :man_shrugging:t2:

Alguien sabe:

1. ¿Qué está causando este error, y
2. ¿Cómo puedo solucionarlo ahora y prevenir que vuelva a ocurrir en el futuro?

Ayuda :slight_smile:

¡Gracias!

¿O se trata más bien de algún otro SQL que intenta insertar en esa tabla?

¿Puedes publicar el código que estás utilizando para realizar una solicitud a la API, sin las credenciales, para que podamos ver cómo haces la solicitud a la API?

Hola @blake, gracias por la respuesta. Solo para asegurarme al 100% de que no era un problema con mi código, preparé la llamada API básica en Insomnia (similar a Postman, pero en mi opinión más simple y fácil). Lamentablemente, los resultados fueron los mismos, pero al menos ahora está muy claro:

Esta es la llamada que preparé para crear un nuevo post (ya he reducido el “número mínimo de palabras en los posts” a 1):

Y estos son los resultados

Y los 2 mensajes de error en los registros de estas llamadas de prueba:

Error 1:

Mensaje (15 copias reportadas)

ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERROR: sintaxis de entrada inválida para el tipo inet: ""
LINE 1: ..._addresses".* FROM "screened_ip_addresses" WHERE ('' <<= ip_...
                                                             ^
)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-2.0.1/lib/patches/db/pg.rb:69:in `exec_params'

Rastreo

rack-mini-profiler-2.0.1/lib/patches/db/pg.rb:69:in `exec_params'
rack-mini-profiler-2.0.1/lib/patches/db/pg.rb:69:in `exec_params'
activerecord-6.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:672:in `block (2 levels) in exec_no_cache'
activesupport-6.0.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
activesupport-6.0.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
activesupport-6.0.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
activerecord-6.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:671:in `block in exec_no_cache'
activerecord-6.0.1/lib/active_record/connection_adapters/abstract_adapter.rb:718:in `block (2 levels) in log'
/usr/local/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'
activerecord-6.0.1/lib/active_record/connection_adapters/abstract_adapter.rb:717:in `block in log'

Error 2:

Mensaje (15 copias reportadas)

No se pudo manejar la excepción en el middleware de la aplicación de excepciones: PG::InvalidTextRepresentation: ERROR: sintaxis de entrada inválida para el tipo inet: ""
LINE 1: ..._addresses".* FROM "screened_ip_addresses" WHERE ('' <<= ip_...
                                                             ^


Rastreo

rack-mini-profiler-2.0.1/lib/patches/db/pg.rb:69:in `exec_params'
rack-mini-profiler-2.0.1/lib/patches/db/pg.rb:69:in `exec_params'
activerecord-6.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:672:in `block (2 levels) in exec_no_cache'
activesupport-6.0.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
activesupport-6.0.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
activesupport-6.0.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
activerecord-6.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:671:in `block in exec_no_cache'
activerecord-6.0.1/lib/active_record/connection_adapters/abstract_adapter.rb:718:in `block (2 levels) in log'
/usr/local/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'
activerecord-6.0.1/lib/active_record/connection_adapters/abstract_adapter.rb:717:in `block in log'

Acabo de crear este usuario hace un momento, así que me pregunto si esto es un error relacionado con los niveles de confianza de alguna manera, o algo más que no esté completamente autorizado para un usuario nuevo. Haré algunas pruebas con eso y veré si puedo averiguar qué permitirá que el post pase por la API.

Pero de todos modos, parece que he descubierto algún tipo de error… ¿?!

Así es como sortee el error… Empecé a experimentar:

  1. Cambié el usuario en mi llamada a la API a ‘system’ y eso funcionó.
  2. Entonces pensé, hmm, y cambié el usuario a un tercer usuario que no había probado. Eso también funcionó.
  3. Luego cambié el usuario de nuevo al nombre de usuario original, lo que significa que estaría repitiendo la llamada a la API exacta que antes arrojaba un error 500. Excepto que ahora funcionó. :man_shrugging:t2:

Si vuelve a ocurrir, veré si puedo averiguar cómo reproducirlo de manera confiable. Mientras tanto, quizás alguien que conozca el código de Discourse mejor que yo :wink: pueda echar un vistazo a esa parte y asegurarse de que no haya errores obvios que llamen la atención.

Hmm, definitivamente hay algo raro ocurriendo aquí. He vuelto a ejecutar mi script y está empezando a crear temas en masa y publicar mensajes… y una vez más, ahora con un usuario diferente, estoy recibiendo el error 500.

Tomé ese nombre de usuario en Insomnia y probé la API… efectivamente, error 500. Cambié a ‘system’ y funcionó… luego volví al usuario original y falló de nuevo con un error 500.

El usuario que provoca el error 500 (y todos mis usuarios importados, excepto ‘system’) tienen nivel TL1, y he ajustado los límites para que TL1 pueda publicar y…

Esto definitivamente parece estar relacionado con el límite de tasa de alguna manera. Sospecharía que nginx, o algo más aguas arriba, podría estar causando el error 500, pero he eliminado todos los límites de tasa de nginx, y el error 500 aparece claramente como ese bug de SQL en los registros de error.

Noté que el error de SQL está fallando en una columna que referencia la dirección IP… ¿podría haber algo extraño ocurriendo con cómo funciona el límite de tasa que provoque este problema? Intenté iniciar sesión con una VPN (para cambiar mi IP), pero aún así obtengo el error 500.

Mientras tanto, veo que el problema está en rack-mini-profiler, que no es necesario. Veamos si puedo desactivarlo y si eso soluciona el problema. … No. Ahora ya no veo el mini-profiler en mi cuenta de administrador, pero sigo obteniendo el mismo error HTTP 500 con los mismos errores en el registro de error :frowning:

Actualización: al cambiar el usuario a TL3, el problema parece desaparecer. Al volver a TL1, vuelve a ocurrir. Estoy probando esta teoría ahora… no. A veces funciona, pero otras veces, incluso si edito manualmente el TL del usuario, este parece quedarse “atascado”.

@blake o alguien más de @staff… ¡ayuda! :wink: ¿Qué más puedo probar? ¿Hay algo que pueda limpiar completamente aquí (relacionado con el código que genera el error) y restablecer a los valores de fábrica?

Parece un posible problema de red, según el rastreo de pila, en ocasiones no se ve ninguna dirección IP para el usuario, ¿de alguna manera? ¿O tienes datos corruptos en la base de datos en admin, logs o direcciones IP filtradas?

De acuerdo: <<= significa ‘LHS contenido dentro de RHS’, por lo que parece que una dirección IP inválida o en blanco está llegando a la aplicación.

(Tengo curiosidad sobre cómo no hay ninguna dirección IP disponible para la aplicación; mi única suposición es que la solicitud está llegando a través de un socket Unix sin encabezados de información de IP reenviada)

Estoy de acuerdo, pero no veo por qué a veces la IP estaría presente y a veces no. En mi script de importación, obtengo este error 500 después de al menos 5-7 llamadas exitosas a la API. Por eso creo que se trata de datos corruptos en la base de datos de alguna manera.

Sí, es extraño. Pero al mismo tiempo, si llamo con un nombre de usuario «incorrecto», falla; si llamo con «system» u otro nombre de usuario, funciona. Así que creo que estamos señalando datos corruptos en mi base de datos, posiblemente.

¿Alguien puede darme algunos comandos sencillos de Ruby para la línea de comandos que pueda escribir para limpiar/restablecer cualquier tabla de la base de datos que pueda estar dañada?

No creo que haya ningún problema con tu base de datos, ya que el error está verificando si hay una dirección IP en blanco en la tabla de direcciones IP filtradas, no si hay direcciones IP vacías en tu base de datos.

Lo interesante, sin embargo, es que este código verifica la existencia de una dirección IP antes de realizar esa solicitud SQL que está generando el error 500.

¿Podrías describir cómo está configurada tu instancia de Discourse? ¿Se trata de una importación? ¿Estás en la última versión? ¿Cuánta memoria RAM tiene? ¿Siguiiste esta guía?

¿Podrías verificar esta configuración del sitio: max new accounts per registration ip? No estoy seguro de que sea relevante en este caso, pero quizás esté causando algún problema.

En tu script masivo, ¿podrías ralentizarlo y añadir una pausa de 1 segundo entre las solicitudes para ver si eso marca la diferencia?

¿Cuál es el propósito de estas llamadas a la API? Si se trata de un script único para crear usuarios y publicaciones importados, ¿no sería mejor un script de importación que se ejecute en el servidor real y que no realice llamadas a la API?

Disculpa por todas las preguntas, pero no hemos encontrado este problema antes y el código relacionado con screened_ip_addresses no se ha actualizado desde hace mucho tiempo. No digo que no haya un error en la base de código en algún lugar, pero tras una mirada rápida, nada destaca en este momento.

Claro: es completamente Docker, en Digital Ocean. Seguí esa excelente guía al pie de la letra.

Claro, acabo de cambiar esa configuración del valor predeterminado de 3 a 99999. Sin cambios, sigo obteniendo el error 500.

Lo intenté, sin cambios. Cabe mencionar que sigo obteniendo el error 500 con SOLO una cuenta “mala”, a través de Insomnia. Así que en este punto, es como si esa cuenta estuviera envenenada; incluso si solo hago esa única llamada a la API de “crear mensaje” con ella (sin ninguna antes ni después), sigo obteniendo el error 500. Pero sí, mi script de importación también está recibiendo el error 500 :wink:

Sí, soy un programador experimentado pero no sé nada de RoR/Ruby, así que no puedo utilizar realmente las opciones listas para usar que ustedes ofrecen, aunque reconozco que probablemente sean superiores a que yo recorra manualmente mis foros existentes y cree usuarios, etc., sobre la marcha mediante la API. Por eso mi publicación en el marketplace… Me encantaría lograr que todo esto funcione por mí mismo, pero también tengo una fecha límite estricta :wink:

Lo entiendo perfectamente, y aprecio tu atención a este asunto.

Así que aquí hay algo que puedo ofrecer y que podría ayudar mucho: dado que es una instalación estándar, no he hecho casi ninguna personalización, Y el error es fácilmente reproducible sin mi código (solo usa Insomnia), Y aún no he lanzado los foros, podría pasarte el acceso root a la instancia de Digital Ocean, mi clave API, etc., y no tengo problema en que te muevas por allí. Mis foros de Discourse son actualmente un montón de categorías vacías y algunos otros mensajes de introducción especiales que hemos configurado, pero básicamente están vacíos y aún no hay usuarios reales (solo administradores). Así que no habría problema si quieres probar cosas, crear/eliminar temas y mensajes, etc.

Esta sería definitivamente la forma más rápida de ver el error en primera persona. Y como estarías allí como root, también podrías manipular cualquier cosa de bajo nivel de Discourse que desees para descubrir por qué está ocurriendo esto.

E

¿Qué sucede si desactivas el SSO?

No hay diferencia, sigue arrojando el error 500.

Otra idea: ¿es posible que cada cuenta para la que ha funcionado sea de administrador? Sé que algunos de los límites de velocidad a nivel de aplicación se eluden para los administradores.

En general, sin embargo, es mucho más fácil simplemente escribir un script de importación. Todo este tema es lo que significa “mucho” :wink:

Hmm, pensé que ya tenía algo… mi usuario de prueba “envenenado”, george21, estaba en TL0. Así que lo cambié a TL1 y entonces funcionó. ¡Ok! ¡Quizás sea eso! Así que entonces cambié a george21 de nuevo a TL0… y ahora ya no está “envenenado”: puede hacer la llamada a la API incluso como TL0.

Ahora ejecutaré mi script de importación de nuevo, y ¡aha! Ahora george21 está lanzando el error 500 en el script de importación. Y cuando lo intento en Insomnia, falla. Así que ahora pondré a george21 de nuevo en TL1 y… sí, puede ejecutar la llamada HTTP.

Así que esto es lo que parece poder reproducir:

  1. Si se realiza una serie de llamadas a la API (?), de alguna manera provoca que una llamada posterior falle con un usuario TL0.
  2. Cambiar al usuario TL0 a TL1 permite que la llamada a la API se complete.
  3. Y extrañamente, luego cambiar a ese mismo usuario de nuevo a TL0 todavía permite que la llamada a la API se complete.
  4. Ejecutar el script de nuevo está bien hasta que vuelve a fallar con otro usuario TL0.

Tenga en cuenta que:

  1. Hasta donde sé, todos los mínimos, etc., para TL0 han sido elevados (es decir, he intentado eliminar cada bloqueo que impediría que un usuario TL0 publique), y
  2. Incluso si esto es un problema con algún tipo de límite de velocidad interno para usuarios TL0, la API no debería lanzar un error 500 y registrar un error SQL en el registro de errores. Así que creo que podemos decir en este punto que definitivamente hay un error en algún lugar.

Sí, um, lo sé, y ya he explicado cuatro veces por qué no estoy escribiendo mi propio script de importación (basado en los ejemplos dados). :wink: Por eso cambié de enfoque.

Y mientras tanto, sigo contribuyendo aquí para ayudar a encontrar y corregir este error. Hoy está afectando a mi script de importación. Mañana podría ser algún script importante que tengas en tu sitio que necesite la API…