Skip to content

fix(discord): delete orphaned auto-thread seed message on fallback failure - #52423

Open
benbarclay wants to merge 1 commit into
mainfrom
fix/discord-auto-thread-orphaned-seed
Open

benbarclay wants to merge 1 commit into
mainfrom
fix/discord-auto-thread-orphaned-seed

Conversation

@benbarclay

Copy link
Copy Markdown
Contributor

Summary

Fixes #52422.

When Discord auto-threading is enabled (discord.auto_thread: true) and thread creation is rate-limited (HTTP 429), _auto_create_thread() posted the "\U0001f9f5 Thread created by Hermes: ..." announcement to the channel before confirming that the fallback create_thread() succeeded. On a 429 the fallback also failed, the function returned None, and the caller responded inline in the main channel \u2014 leaving an orphaned "Thread created" announcement with no thread behind it.

Production log for the reported case:

WARNING ...discord.adapter: [Discord] Auto-thread creation failed.
  Direct error:   Too many requests. Retry in 278.53 seconds.
  Fallback error: Too many requests. Retry in 222.97 seconds.

Fix

In the fallback except branch, delete the seed message if create_thread() then fails, so the announcement only ever survives when a real thread exists. Deletion failures are swallowed at debug level (best-effort cleanup).

seed_msg = None
try:
    seed_msg = await message.channel.send("\U0001f9f5 Thread created by Hermes: **...**")
    thread = await seed_msg.create_thread(...)
    return thread
except Exception as fallback_error:
    if seed_msg is not None:
        try:
            await seed_msg.delete()
        except Exception as cleanup_error:
            logger.debug(...)
    logger.warning(...)
    return None

Test Plan

New tests/gateway/test_discord_auto_thread_orphan_seed.py covers three paths:

  • direct create 429 + fallback create 429 \u2192 seed deleted, returns None
  • direct create 429 + fallback create succeeds \u2192 seed kept, thread returned
  • direct create succeeds \u2192 no seed posted, no fallback

Verified the new test fails against unpatched code (asserts seed.deleted is True) and passes with the fix. Existing tests/gateway/test_discord_double_dispatch.py (12 tests, same function) stays green.

tests/gateway/test_discord_auto_thread_orphan_seed.py ...   3 passed
tests/gateway/test_discord_double_dispatch.py ............  12 passed

Notes / follow-up

This fixes the immediate user-visible defect (orphaned announcement + inline reply). A larger follow-up would be to back off or suppress auto-threading under sustained 429s rather than retrying per-message; out of scope here.

…ilure

When auto-threading is rate-limited, _auto_create_thread() posted the
'Thread created by Hermes' announcement before confirming the fallback
create_thread() succeeded. On a 429 the announcement was left orphaned
and the agent replied inline, so users saw 'Thread created' with no
thread behind it.

Delete the seed message when the fallback create_thread() fails so the
announcement only survives when a real thread exists.

Adds tests/gateway/test_discord_auto_thread_orphan_seed.py covering the
three paths (fallback-fail deletes seed, fallback-success keeps seed,
direct-success posts no seed).

Fixes #52422
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: fix/discord-auto-thread-orphaned-seed vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11270 on HEAD, 11270 on base (➖ 0)

🆕 New issues (3):

Rule Count
invalid-assignment 1
unresolved-import 1
unresolved-attribute 1
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`
tests/gateway/test_discord_auto_thread_orphan_seed.py:24: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/gateway/test_discord_auto_thread_orphan_seed.py:83: [unresolved-attribute] unresolved-attribute: Module `discord` has no member `MessageType`

✅ Fixed issues (2):

Rule Count
unresolved-attribute 2
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
run_agent.py:2989: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`

Unchanged: 5941 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery platform/discord Discord bot adapter P2 Medium — degraded but workaround exists sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jun 25, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Clean fix for Discord auto-threading. When thread creation fails (commonly a 429 rate-limit), the seed announcement message was left orphaned in the channel. The fix deletes the orphaned seed message so the announcement only survives when a real thread exists.

Looks Good

  • Correct initialization of seed_msg = None before the try block to handle the variable being potentially unbound in the except handler
  • Graceful cleanup: seed_msg.delete() wrapped in its own try/except with debug logging
  • 143-line test file covers the key scenarios: direct error with fallback success, direct error with fallback failure (orphan cleanup), no seed message to clean
  • Minimal diff (2 files, 161 additions)

Reviewed by Hermes Agent (cron)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/discord Discord bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discord auto-thread: orphaned “Thread created by Hermes” message + inline reply when thread creation is rate-limited

3 participants