Discord bot can't access previous channel messages after restart (Node.js)

I’m building a Discord bot using Node.js and running into a problem. When my bot restarts, it loses access to messages that were sent before the reboot. I need the bot to count all messages in a channel, including the ones from before it went offline.

const discord = require('discord.js-commando');

module.exports = class MessageCounter extends discord.Command {
    constructor(client) {
        super(client, {
            name: 'countmsg',
            group: 'utilities',
            memberName: 'countmsg',
            description: 'Shows total message count in current channel'
        });
    }
    async run(message, parameters) {
        message.channel.send(`Total messages: ${message.channel.messages.size}`);
    }
}

Here’s what happens: I post several messages in a channel, then restart my bot and run the command. Instead of showing all messages, it only counts 1 (the command message itself). How can I make the bot fetch and count all previous messages in the channel?

Your problem is that the cache gets cleared when you restart. The messages.size property only displays the messages currently present in the bot’s local cache, not the actual channel history. To retrieve the full history, you must fetch messages directly from Discord’s servers. Oscar64 did mention the 100 message limit for each request, but you can make multiple requests to get all messages. Here’s an improved solution:

async run(message, parameters) {
    let totalCount = 0;
    let lastMessageId;
    
    while (true) {
        const options = { limit: 100 };
        if (lastMessageId) options.before = lastMessageId;
        
        const fetched = await message.channel.messages.fetch(options);
        if (fetched.size === 0) break;
        
        totalCount += fetched.size;
        lastMessageId = fetched.last().id;
    }
    
    message.channel.send(`Total messages: ${totalCount}`);
}

This approach will ensure you count all messages in the channel’s history. However, be cautious with channels having thousands of messages, as this method could take a while and might hit rate limits.

The issue arises because message.channel.messages.size only accounts for messages currently in memory, which gets reset when the bot restarts. To retrieve the entire message history, including those sent before the bot was restarted, you should use the fetchMessages() method from Discord’s API.

Here’s an updated approach:

async run(message, parameters) {
    const fetchedMessages = await message.channel.messages.fetch({ limit: 100 });
    message.channel.send(`Total messages: ${fetchedMessages.size}`);
}

Be aware that Discord limits each fetch to 100 messages. If you need to access more, implement pagination with the before parameter. Additionally, fetching a large number of messages can be slow and may hit rate limits, so consider adding caching if this command will be used frequently.

Quick tip - check if your bot has VIEW_CHANNEL and READ_MESSAGE_HISTORY permissions. Fetch methods fail silently without proper perms and you’ll just get empty results. Been there, super frustrating to debug.

The Problem: Your Discord bot loses message counts when it restarts because it relies on the local cache, which is cleared on reboot. The message.channel.messages.size property only reflects messages currently in the bot’s memory, not the complete channel history. Your goal is to count all messages in a channel, regardless of when they were sent. Simply fetching messages with a limit of 100 is insufficient for channels with more messages.

:thinking: Understanding the “Why” (The Root Cause):

The core issue lies in how Discord.js (and discord.js-commando) handles message caching. The cache is a local, temporary storage for recent messages, improving performance. However, this cache is volatile—it’s cleared whenever your bot restarts. To obtain a complete message count, you must directly query the server’s message history, which is stored separately from the cache. Attempting to only use cached information results in an incomplete count.

:gear: Step-by-Step Guide:

This guide explains how to reliably fetch and count all messages from a Discord channel, handling potential limitations of the Discord API. The solution involves iterative fetching because the Discord API limits the number of messages retrieved per request.

Step 1: Implement Iterative Message Fetching:

This code fetches messages in batches of 100 until no more messages are found. Replace 'your_channel_id' with the actual ID of the channel where you want to count messages. Note that this method will not count messages older than 14 days. Consider using a database for longer-term message tracking.

async run(message, parameters) {
    let totalCount = 0;
    let lastMessageId;

    while (true) {
        const options = { limit: 100 };
        if (lastMessageId) options.before = lastMessageId;

        try {
            const fetched = await message.channel.messages.fetch(options);
            if (fetched.size === 0) break;

            totalCount += fetched.size;
            lastMessageId = fetched.last().id;
        } catch (error) {
            console.error("Error fetching messages:", error);
            // Implement error handling, such as exponential backoff for rate limits
            break; //Exit loop on error to prevent indefinite retry
        }
    }

    message.channel.send(`Total messages: ${totalCount}`);
}

Step 2: Verify Bot Permissions:

Ensure your bot has the necessary permissions (VIEW_CHANNEL and READ_MESSAGE_HISTORY) for the target channel. Lacking these permissions will prevent fetching any messages. Check your Discord server’s role settings to assign these permissions to your bot.

Step 3: Handle Rate Limits (Important!):

Fetching a large number of messages can trigger rate limits from the Discord API. The provided code lacks explicit rate limit handling. For production bots, implement exponential backoff: if a rate limit error occurs, wait an increasing amount of time before retrying the fetch. Libraries like discord.js typically provide built-in rate limit handling, but it’s essential to understand how it works.

:mag: Common Pitfalls & What to Check Next:

  • Rate Limits: The most common problem is hitting Discord’s API rate limits. Implement robust rate limit handling as described above. Using a database is advisable for frequent message counting.

  • Permissions: Double-check that your bot has the VIEW_CHANNEL and READ_MESSAGE_HISTORY permissions in the relevant channel.

  • Message Age: Remember that the Discord API only allows fetching messages up to the last two weeks (14 days). For older messages, a database solution is necessary.

  • Error Handling: The provided code includes basic error handling, but more sophisticated error handling (e.g., logging errors to a file, using a centralized error reporting service) may be necessary in a production environment.

  • Channel Type: The behavior of message fetching may differ slightly based on the type of channel (text, voice, announcement, etc.).

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

heads up - fetching thousands of messages will get you rate limited fast. store the count in a database instead and update it when new messages arrive. no need to fetch everything after restarts

Hit this exact problem with my first Discord bot. Cache clearing on restart is annoying, right? The fetch solutions work, but heads up - Discord’s API only grabs messages from the last 2 weeks in text channels. Found this out the hard way when my bot completely missed a month’s worth of data. If you need counts going back further, you’ll have to track messages in real-time with a database. Set up a messageCreate listener to increment your counter as new messages come in, then just pull from your database instead of hitting Discord’s API.

Discord.js cache behavior trips up everyone at first. You’re using the old discord.js-commando framework, which has some caching quirks. The cache only keeps messages from when your bot was online - restart it and everything’s gone. Besides the fetching methods already mentioned, different channel types handle message retention differently. Voice channels and announcement channels don’t work the same as regular text channels for message history. Your bot can only fetch messages from channels it has read permissions for, and some servers lock down message history access. If you go with fetching, add exponential backoff for rate limits - Discord’s API gets pickier during busy times. For production bots, I’d mix real-time tracking with occasional validation fetches. That’s usually the most reliable setup.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.