Files
xmpp-server-prosody/references/slidge-flood-invites-and-roster.md
2026-09-06 13:51:11 +00:00

5.1 KiB

Slidge invite flood, roster loss and group-join "unavailable" — diagnosis playbook

Symptom cluster (seen 2026-08-29 on nixg.ru, estorozhenko@ account):

  1. After a server restart the Telegram contacts are GONE from the client roster and even telegram.nixg.ru no longer shows.
  2. Client (Pidgin) got "миллион запросов на подключение к чату" (a flood of group-join invitations), each join failing with «Получатель недоступен» / recipient-unavailable.
  3. Joining group-<id>@telegram.nixg.ru/<nick> errors.

Root cause chain (verified in logs + slidge 0.4.2 source):

Layer 1 — roster is NOT lost on the server

Before assuming data loss, query the roster from a fresh slixmpp client:

import asyncio, slixmpp
async def main():
    bot = slixmpp.ClientXMPP('user@dom','pass')
    import ssl; ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
    bot.ssl_context=ctx
    await bot.connect(('localhost',5222))
    iq = bot.make_iq_get(); iq['id']='roster3'
    # NOTE: roster get must have NO 'to' attribute — sending to the server domain
    # (to=nixg.ru) returns service-unavailable!
    iq.xml.append(iq.xml.makeelement('{jabber:iq:roster}query',{}))
    # ... await result, count items with 'telegram.nixg.ru' in jid
asyncio.run(main())

Pitfall: make_iq_get() + roster query sent WITH to=<server domain> → service-unavailable (false negative, made me suspect mod_roster was broken). Without to it works and returned 1602 telegram contacts. Conclusion: server side is intact; the CLIENT had dropped the roster view after reconnect. Fix: disable/re-enable the account in the client (Pidgin) or restart it — client re-downloads the roster on login.

Layer 2 — mod_privilege (XEP-0356) is 0.12-only API; crashes on 0.11

prosody/logs/prosody.err showed: mod_privilege.lua: ... attempt to call method 'send_iq' (a nil value). The prosody-modules mod_privilege.lua is written against Prosody 0.12 (module:send_iq(wrapped_iq, newsession):next(...)). On 0.11.9 there is no module:send_iq, so every privileged IQ from the bridge crashes the handler.

Effect on slidge: it uses xep_0356.send_privileged_iq() to write the user's PEP bookmarks. With mod_privilege broken the write times out → room.add_to_bookmarks() hits its failure branch and calls send_gateway_invite() for EVERY group (because the bookmark could not be set automatically). That is the "million join invites" — each invite is group-<id>@telegram.nixg.ru, and trying to join it while the bookmark write never completed gives recipient-unavailable.

Layer 3 — slidge first-run sync floods the Telegram API

First login after registering a large account: slidge syncs hundreds of chats/contacts via MTProto and hits Flood in get_chat/get_users/ get_chat_member ... sleep for 11-22 seconds (slidgram handle_flood). This slows joins to ~20+ s and contributes to join timeouts. It is transient — after the cache fills, floods stop. Not a bug; do not restart the bridge to "fix" it (each restart re-runs part of the sync and can re-trigger floods, plus Client is already terminated noise on stop).

Layer 4 — user preference toggle: always_invite_when_adding_bookmarks

user_account.preferences in slidge.sqlite had: {"sync_avatar": true, "always_invite_when_adding_bookmarks": true, ...}. With bookmarks broken (Layer 2) every add triggers an invite because of this flag. Turning it off stops the invite spam even while mod_privilege is broken:

import sqlite3; con=sqlite3.connect('/var/lib/slidge/slidge.sqlite')
con.execute("UPDATE user_account SET preferences=... " ) # drop the flag; restart icq-slidgram

BUT the real fix is Layer 2/0.12 upgrade — the bookmark write then succeeds and no fallback invites are sent at all.

Diagnosing orders (do these FIRST)

  1. docker logs icq-slidgram | grep -iE 'Group|MDS|flood|privilege' — look for Flood in get_chat and Error while trying to subscribe to the MDS node.
  2. grep -iE 'mod_privilege|send_iq|attempt to' /opt/icq/logs/prosody.err — the 0.12-API crash.
  3. Roster reality check via slixmpp (Layer 1) — proves server data intact.
  4. sqlite3 room table: SELECT * FROM room WHERE legacy_id LIKE '%<id>%' — confirmed group-1001698123474 = "Денис Сорокин (channel)", muc_type=CHANNEL, jid_localpart=group-1001698123474. Room known to the bridge; join failure was purely the bookmark/privilege chain above.

Permanent fixes (in priority order)

  • Upgrade Prosody to 0.12 (built-in mod_privilege) — see prosody-012-upgrade-path.md.
  • Do NOT hand-patch community mod_privilege to fake send_iq on 0.11: a stub that ACKs without forwarding still leaves bookmarks unwritten (slidge waits for the forwarded result) → invite flood persists. A stub was tried and still produced Error while trying to subscribe to the MDS node.
  • Alternative: give the bridge roster access via older XEP-0356-free methods (roster push through regular roster set works — slidge RosterBackend), so contacts DO appear; only bookmarks/auto-invites stay broken until 0.12.