Errore SQL con `screened_ip_addresses` (l'API restituisce 500)

Ciao amici,

l’API mi restituisce un errore 500 quando provo a creare un nuovo post (in un argomento esistente). Nei log vedo:

ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERROR:  sintassi di input non valida per il 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'

Impossibile gestire l'eccezione nel middleware dell'app di eccezione: PG::InvalidTextRepresentation: ERROR:  sintassi di input non valida per il tipo inet: ""
LINE 1: ..._addresses".* FROM "screened_ip_addresses" WHERE ('' <= ip_...
                                                             ^

Ecco la mia lista degli IP filtrati: oltre allo screenshot qui sotto, ho anche inserito in whitelist l’IP della macchina che chiama l’API. (Sto utilizzando una chiave API a livello di sistema per importare in massa vecchi argomenti/messaggi dal mio vecchio software di forum.)

Per scherzo, ho anche chiesto all’API la lista degli IP filtrati… stessi risultati. (https://mydiscourse.com/admin/logs/screened_ip_addresses.json)

Non sono sicuro di cosa altro controllare. :man_shrugging:t2:

Qualcuno sa:

1. Cosa sta causando questo errore, e
2. Come posso risolverlo ora ed evitare che accada in futuro?

Aiuto :slight_smile:

Grazie!

O si tratta di qualcos’altro, come un’altra query SQL che cerca di inserire dati in quella tabella?

Puoi pubblicare il codice che stai utilizzando per effettuare una richiesta API, rimuovendo le credenziali, in modo che possiamo vedere come stai eseguendo la richiesta?

Ciao @blake, grazie per la risposta. Per essere assolutamente certo che non si trattasse di un problema nel mio codice, ho preparato la chiamata API di base in Insomnia (simile a Postman ma, a mio avviso, più semplice e intuitiva). Purtroppo, i risultati sono gli stessi, ma ora è molto chiaro:

Ecco la chiamata che ho preparato per creare un nuovo post (ho già impostato il “numero minimo di parole nei post” a 1):

Ecco i risultati

E i 2 messaggi di errore nei log generati da queste chiamate di test:

Errore 1:

Messaggio (15 copie riportate)

ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERRORE: sintassi di input non valida per il 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'

Backtrace

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'

Errore 2:

Messaggio (15 copie riportate)

Impossibile gestire l'eccezione nel middleware dell'app di eccezione: PG::InvalidTextRepresentation: ERRORE: sintassi di input non valida per il tipo inet: ""
LINE 1: ..._addresses".* FROM "screened_ip_addresses" WHERE ('' <<= ip_...
                                                             ^


Backtrace

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'

Ho appena creato questo utente un momento fa, quindi mi chiedo se si tratti di un bug legato ai livelli di fiducia, in qualche modo, o di qualcos’altro per cui un nuovo utente non ha ancora l’autorizzazione completa. Farò qualche esperimento al riguardo per vedere se riesco a capire cosa permetterà al post di passare attraverso l’API.

In ogni caso, sembra che io abbia portato alla luce un qualche tipo di bug… ?!

Quindi ecco come ho aggirato il bug… Ho iniziato a fare esperimenti:

  1. Ho modificato l’utente nella mia chiamata API in ‘system’ e ha funzionato
  2. Così ho pensato, hmm, e ho cambiato l’utente in un terzo utente che non avevo ancora provato. Anche quello ha funzionato.
  3. Poi ho riportato l’utente al nome originale, il che significa che stavo ripetendo esattamente la chiamata API che prima aveva generato un errore 500. Solo che ora ha funzionato. :man_shrugging:t2:

Se si ripresenterà, cercherò di capire come riprodurlo in modo affidabile. Nel frattempo, forse qualcuno che conosce il codice di Discourse meglio di me :wink: può dare un’occhiata a quella parte e assicurarsi che non ci siano bug evidenti che saltano all’occhio.

Hmmm c’è sicuramente qualcosa di strano in corso qui. Ho riavviato il mio script e sta iniziando a creare in blocco argomenti e pubblicare messaggi… e ancora una volta, ora con un utente diverso, ricevo l’errore 500.

Ho inserito quel nome utente in Insomnia e testato l’API… come previsto, errore 500. Ho cambiato a ‘system’ e tutto funziona… poi sono tornato al nome utente originale e di nuovo fallisce con un 500!

L’utente che genera l’errore 500 (e tutti i miei utenti importati tranne ‘system’) hanno il livello TL1, e ho modificato i limiti in modo che TL1 possa pubblicare e…

Questo fa decisamente pensare a un problema legato al rate limiting, in qualche modo? Sospetterei che nginx, o qualcosa a monte, stia causando l’errore 500, ma ho rimosso tutto il rate limiting da nginx e l’errore 500 appare chiaramente come quel bug SQL nei log degli errori.

Ho notato che l’errore SQL si verifica intorno a una colonna che fa riferimento all’indirizzo IP… potrebbe esserci qualcosa di strano nel modo in cui il rate limiting funziona che potrebbe causare questo problema? Ho provato ad accedere con una VPN (per cambiare il mio IP) ma ricevo comunque l’errore 500.

Nel frattempo, vedo che il problema è in rack-mini-profiler, che non è necessario. Vediamo se riesco a disattivarlo e se questo risolve il problema. … No. Ora non vedo più il mini-profiler sul mio account amministratore, ma ricevo ancora lo stesso HTTP 500 con gli stessi errori nel log degli errori :frowning:

Aggiornamento: cambiando l’utente a TL3, il problema sembra scomparire. Ripassando a TL1 si ripresenta. Sto testando questa teoria ora… no. A volte funziona, ma altre volte, anche se modifico manualmente il TL dell’utente, sembra che l’utente rimanga “bloccato”.

@blake o qualcun altro di @staff… aiuto! :wink: cosa posso provare ancora? C’è qualcosa che posso resettare completamente qui (relativo al codice che genera l’errore) e riportare alle impostazioni di fabbrica?

A mio avviso sembra un possibile problema di rete: a volte, per qualche motivo, non viene rilevato alcun indirizzo IP per l’utente. Oppure ci sono dati errati nel database relativi a amministratori, log o indirizzi IP filtrati?

Concordo - <<= significa “LHS contenuto in RHS”, quindi sembra che un indirizzo IP errato o vuoto stia raggiungendo l’app.

(Sono curioso di sapere come tu non abbia alcun indirizzo IP disponibile per l’app; la mia unica ipotesi è che la richiesta arrivi tramite una socket Unix senza un header con informazioni sull’IP inoltrato)

Concordo, ma non capisco perché a volte l’IP ci sia e a volte no. Nel mio script di importazione, ottengo questo errore 500 dopo almeno 5-7 chiamate API andate a buon fine prima di esso. Per questo motivo penso che si tratti di dati corrotti nel database, in qualche modo.

Sì, è strano. Ma allo stesso tempo, se chiamo con un nome utente “errato”, fallisce; se chiamo con “system” o un altro nome utente, funziona. Quindi penso che stiamo indicando dati corrotti nel mio database, forse.

Qualcuno può indicarmi dei semplici comandi da riga di comando Ruby che posso digitare per cancellare/reimpostare eventuali tabelle del database che potrebbero essere danneggiate?

Non credo che ci sia qualcosa di sbagliato nel tuo database, poiché l’errore riguarda la verifica della presenza di un indirizzo IP vuoto nella tabella degli indirizzi IP filtrati, non la presenza di indirizzi IP vuoti nel tuo database.

La cosa interessante è che questo codice verifica l’esistenza di un indirizzo IP prima di eseguire la richiesta SQL che genera l’errore 500.

Puoi descrivere come è configurata la tua istanza di Discourse? È stata importata? Stai utilizzando l’ultima versione? Quanta RAM ha? Hai seguito questa guida?

Puoi controllare questa impostazione del sito: max new accounts per registration ip? Non sono sicuro che sia rilevante in questo caso, ma potrebbe essere la causa del problema.

Nel tuo script in batch, potresti rallentarlo inserendo una pausa di 1 secondo tra le richieste e vedere se questo fa la differenza?

Qual è lo scopo di queste chiamate API? Se si tratta di uno script una tantum per creare utenti e post importati, forse sarebbe meglio utilizzare uno script di importazione eseguito direttamente sul server, senza effettuare chiamate API?

Scusa per tutte le domande, ma non abbiamo mai riscontrato questo problema in precedenza e il codice relativo a screened_ip_addresses non è stato aggiornato da molto tempo. Non sto dicendo che non ci siano bug nel codice, ma dopo una rapida occhiata al momento nulla risalta in particolare.

Certo — è interamente basata su Docker, su Digital Ocean. Ho seguito quella guida eccellente alla lettera.

Certo, ho appena modificato quell’impostazione passando dal valore predefinito 3 a 99999. Niente cambia, ricevo ancora l’errore 500.

L’ho provato, nessuna differenza. Nota che ricevo ancora l’errore 500 con UN solo account “difettoso”, usando Insomnia. Quindi a questo punto è come se quell’unico account fosse compromesso, e anche se faccio solo quella singola chiamata API “create message” (nessuna prima o dopo), ricevo comunque l’errore 500. Ma sì, anche il mio script di importazione riceve l’errore 500 :wink:

Sì, sono un programmatore esperto ma non conosco affatto RoR/Ruby, quindi non posso davvero utilizzare le soluzioni pronte all’uso che offrite, anche se riconosco che sono probabilmente superiori rispetto al mio dover manualmente navigare nei forum esistenti e creare utenti, ecc., al volo tramite API. Quindi il mio post sul marketplace… Mi piacerebbe molto far funzionare tutto da solo, ma ho anche una scadenza rigida :wink:

Capisco perfettamente, e apprezzo molto la tua attenzione a questo problema.

Quindi ecco qualcosa che posso offrire e che potrebbe essere molto utile: dato che si tratta di un’installazione standard, non ho fatto quasi nessuna personalizzazione, E il bug è facilmente riproducibile senza il mio codice (basta usare Insomnia) E non ho ancora lanciato i forum, potrei passarti il login root dell’istanza di Digital Ocean, la mia chiave API, ecc., e non ho alcun problema se vuoi smanettare lì dentro. I miei forum Discourse sono attualmente un mucchio di categorie vuote e alcuni altri messaggi di introduzione speciali che abbiamo impostato, ma è praticamente vuoto e non ci sono ancora utenti reali (solo amministratori). Quindi va benissimo se vuoi fare test, creare/cancellare argomenti e messaggi, ecc.

Questo sarebbe sicuramente il modo più veloce per vedere il bug di persona. E poi, dato che sarai lì come root, potrai anche smanettare con qualsiasi cosa a basso livello di Discourse desideri, per scoprire perché sta accadendo.

E

Cosa succede se disabiliti l’SSO?

Nessuna differenza, continua a restituire l’errore 500.

Un’altra idea: è possibile che ogni account per cui ha funzionato sia un amministratore? So che alcuni limiti di velocità a livello di applicazione vengono aggirati per gli amministratori.

In generale, però, è molto più semplice scrivere direttamente uno script di importazione. Questo intero argomento è l’esempio di cosa significhi “molto” :wink:

Mmm, pensavo di aver trovato qualcosa… il mio utente di test “avvelenato”, george21, era a TL0. Quindi l’ho cambiato a TL1 e poi ha funzionato. Ok! Forse è questo! Quindi ho riportato george21 a TL0… e ora non è più “avvelenato”—può effettuare la chiamata API anche come TL0.

Ora eseguirò di nuovo il mio script di importazione e, ecco fatto. Ora george21 genera l’errore 500 nello script di importazione. E quando provo in Insomnia, fallisce. Quindi rimetto george21 a TL1 e… sì, può eseguire la chiamata HTTP.

Ecco quindi ciò che sembra essere possibile riprodurre:

  1. Se viene effettuata una serie di chiamate API (?), in qualche modo ciò fa fallire una successiva chiamata API con un utente TL0.
  2. Cambiare l’utente TL0 in TL1 permette alla chiamata API di passare.
  3. E stranamente, cambiare di nuovo lo stesso utente a TL0 permette ancora alla chiamata API di passare.
  4. Eseguire di nuovo lo script va bene finché non fallisce di nuovo con un altro utente TL0.

Si noti che:

  1. Per quanto ne so, tutti i minimi richiesti per TL0 sono stati alzati (cioè ho cercato di rimuovere ogni blocco che impedirebbe a un utente TL0 di pubblicare), e
  2. Anche se si trattasse di un problema con qualche tipo di limite di velocità interno per gli utenti TL0, l’API non dovrebbe generare un errore 500 e inserire un errore SQL nel registro degli errori. Quindi penso che possiamo dire a questo punto che c’è sicuramente un bug da qualche parte.

Sì, lo so, e ho già spiegato quattro volte perché non sto scrivendo il mio script di importazione (basandomi sugli esempi forniti). :wink: Da qui il mio cambio di approccio.

Nel frattempo, continuo a contribuire qui per cercare di trovare e correggere questo bug. Oggi sta influenzando il mio script di importazione. Domani potrebbe essere uno script importante che hai sul tuo sito e che necessita dell’API…