InteractionCollector timeout behavior and memory disposal in discord.js v14
0 reputation · 23 Jan 2022, 03:47 UTC
0 reputation · 23 Jan 2022, 03:47 UTC
When using an InteractionCollector with a time option in discord.js v14, the collector stops automatically after the period elapses and emits an 'end' event with reason 'time'. The collected interactions remain in the collector’s collected collection unless the dispose option is set to true, which clears the collection on end. Additionally, deferring an interaction and later cancelling it with interaction.deleteReply() throws a DiscordAPIError if the interaction has already been replied to or deleted, and discord.js does not provide an abort signal for interaction.reply() or interaction.editReply(), requiring manual timeout handling.
Given these behaviors, developers must decide how to manage memory usage and error handling for time‑limited collectors and deferred interactions.
dispose flag always be enabled when a time limit is set to prevent accumulation of collected items?deleteReply() without checking interaction.replied?reply and editReply calls in the absence of an abort signal?35275 reputation · 23 Jan 2022, 06:54 UTC
1. Should dispose:true always be enabled when a time limit is set?
Enable dispose:true whenever you do not need the collected interactions after the collector ends. The flag only clears the collector.collected collection once the end event fires, so it prevents memory buildup in long‑running bots. If you intentionally want to keep the interactions for later processing, set dispose:false and handle the cleanup yourself.
2. Is catching DiscordAPIError from deleteReply() enough?
Relying solely on error catching works but can produce noisy logs. Checking interaction.replied (or interaction.deferred) before calling deleteReply() filters out the obvious cases where the reply is already sent or removed, reducing unnecessary error handling code. It is a good practice to combine both checks and error handling.
3. Recommended pattern for custom timeout on reply / editReply?
Wrap the call in Promise.race with a timeout promise. Clear the timer if the original promise resolves first to avoid orphan timers. Example:
async function replyWithTimeout(interaction, options, ms) {
const timeout = setTimeout(() => {
throw new Error('reply timed out after ' + ms + 'ms');
}, ms);
try {
return await Promise.race([
interaction.reply(options),
new Promise((_, reject) => {
timeout;
reject(new Error('reply timed out'));
})
]);
} finally {
clearTimeout(timeout);
}
}
Use a similar wrapper for editReply. Adjust ms to account for network latency and typical API response times.
dispose:true clears the collected collection after end.deleteReply() throws DiscordAPIError if the reply is already sent or deleted.reply() or editReply().time: 5000 and dispose:true. After the end event, check collector.collected.size === 0.interaction.reply() followed by interaction.deleteReply() in a try/catch block. Log the error code to confirm it is 10008 (unknown message) or 10014 (message deleted).replyWithTimeout and set ms to 3000. Observe that a delayed reply exceeding 3s results in the rejection error.Do you need to keep the collected interactions after the collector ends (e.g., for audit or replay purposes)? If so, you should set dispose:false and manually clear the collection when appropriate.
dispose:true to avoid memory leaks unless you have a specific need to retain data.interaction.replied checks with error catching for robust deleteReply handling.Promise.race with clear timers for custom timeouts on reply and editReply.Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.