Why My Discord Bot Was Announcing Villager Funerals
Messages started appearing in our Discord channel that nobody asked for:
Villager class_1646['Villager'/297305, l='ServerLevel[TubaBoneWorld2025]',
x=-137.30, y=96.00, z=-399.70] died, message: 'Villager was squished too much'
Nobody wants a notification every time a wandering traderâs llama meets its end.
The Setup
My Minecraft server runs a Discord bot that bridges chat between the game and a Discord channel. A log watcher monitors the server log file in real-time, forwarding relevant messagesâplayer joins, achievements, deathsâto Discord. Players love the integration. What they donât love is getting pinged for every villagerâs unfortunate encounter with a piston.
The Investigation
My first thought was the new datapack Iâd installed for player head drops, but its contents only touch loot tablesâno chat logic. The real culprit was hiding in my log watcher:
class MinecraftLogHandler(FileSystemEventHandler):
DEATH_PATTERN = re.compile(r'\[Server thread/INFO\]: (.+?) (died|was slain|was killed)')
def process_log_line(self, line):
death_match = self.DEATH_PATTERN.search(line)
if death_match:
self.send_to_discord(f"{death_match.group(1)} {death_match.group(2)}")
The pattern was too greedy. The regex (.+?) captures any characters until it hits a death keyword. When the server logs a villager death, the pattern happily matches Villager class_1646['Villager'/297305...] as the âplayerâ name. It doesnât know the difference between Steve and an internal mob identifierâit just sees text followed by a death word.
The Fix
The solution was specificity:
# Player names are 3-16 chars, alphanumeric with underscores only
PLAYER_DEATH_PATTERN = re.compile(
r'\[Server thread/INFO\]: ([A-Za-z0-9_]{3,16}) (died|was slain by|was killed by|'
r'drowned|burned to death|fell from|was blown up by|hit the ground too hard|'
r'was shot by|starved to death|suffocated in|was squished)'
)
Minecraft player names follow strict rules: 3-16 characters, alphanumeric with underscores. Mob identifiers contain class names, brackets, coordinates, and quotes. By requiring the simpler pattern, we filter out the noise.
After deploying, the Discord channel went quiet. No more villager obituariesâjust the player deaths we actually wanted to see.
What I Learned
Regex greed causes bugs. When parsing logs, be as specific as possible about what youâre matching. A broad pattern that âmostly worksâ will eventually capture something unexpected.
Data has structureâuse it. The difference between Steve and Villager class_1646['Villager'/297305...] is obvious to humans but requires explicit rules for code. Identify structural differences and encode them.
Check your assumptions. I assumed only player events would match player-focused patterns. The regex wasnât failing on edge casesâit was succeeding on an entirely different category of data I hadnât anticipated.
Sometimes the most valuable debugging sessions are the ones where you fix the thing you didnât know was broken.