Error: Cannot message this thread until after the post author has sent an initial message.

I'm encountering the following error:
DiscordAPIError[40058]: Cannot message this thread until after the post author has sent an initial message.
DiscordAPIError[40058]: Cannot message this thread until after the post author has sent an initial message.
I understand the error. However, I'm struggling with how to properly handle this. My use case is that the bot should send a message immediately after a thread is created. The issue typically arises when the initial message includes a large file or video upload, which delays the actual posting. My question is: How can I detect when the initial message has been fully sent and the thread is ready to receive bot messages? I’ve tried using a setTimeout with 1 second, but that’s not consistently enough. Is there a proper event or listener that signals when the thread becomes active or the initial message is finalized? Any advice or best practices would be appreciated.
15 Replies
d.js toolkit
d.js toolkit3w ago
- What's your exact discord.js npm list discord.js and node node -v version? - Not a discord.js issue? Check out #other-js-ts. - Consider reading #how-to-get-help to improve your question! - Explain what exactly your issue is. - Post the full error stack trace, not just the top part! - Show your code! - Issue solved? Press the button!
Steve
Steve3w ago
Maybe check if there are a minum amount of messages sent in the channe?
Lixeiro Charmoso
Lixeiro CharmosoOP3w ago
Idk.... but worth a try
Redboot
Redboot3w ago
I've never done what you're trying to do, but would it make sense to listen to threadCreate, store the thread ID on your side, and then listen to messageCreate for a message in a thread with that same ID?
edocsil
edocsil3w ago
I was thinking similar, but I don't even think you necessarily need to store the thread ID... Just trigger off messages that match their thread IDs. Edit: Or just Message.hasThread actually ThreadChannel.awaitMessage and ThreadChannel.fetchStarterMessage could also be used in a solution, but those aren't events. Or checking whether ThreadChannel.lastMessageId exists
Redboot
Redboot3w ago
I just ran a test, and fetchStarterMessage is not the actual first message in the thread. it's the thread title.
edocsil
edocsil3w ago
Works on my machine but maybe there's a misunderstanding about what the "first message" is. For forums it would be the post itself yeah
Redboot
Redboot3w ago
He said "thread," so I ran the test in a thread. The part underlined in red is the "first" message. I haven’t tested it, but if I understand correctly, Discord wants the initial message (which is actually the second message) to be sent
No description
edocsil
edocsil3w ago
Seems I was mistaken and what's considered the "starter message" changes depending on whether the thread was created off an existing message. If it's made at the same time then yeah apparently it's the title
Lixeiro Charmoso
Lixeiro CharmosoOP3w ago
I tried this, but seems that didnt work
client.on("threadCreate", async (thread) => {
try {
if (thread.parentId !== process.env.FREE_SCRIPTS_CHANNEL_ID) return;
if (!thread.joinable) return;
await thread.join();

// Create the "Mark as Solved" button
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId("mark_as_solved")
.setLabel("Mark post as solved")
.setStyle(ButtonStyle.Primary),
);

// Wait for the first user message in the thread
const filter = msg => msg.threadId === thread.id && !msg.author.bot;
thread.awaitMessages({ filter, max: 1, time: 300000, errors: ["time"] }) // wait up to 5 minutes
.then(async collected => {
const botMessage = await thread.send({
content: getConstSupportGuidelinesMessage(thread.ownerId),
components: [row],
});

thread.botMessageId = botMessage.id;
})
.catch(() => {
console.warn(`No user message was sent in thread ${thread.id} after creation.`);
});


} catch (error) {
console.error(`Error sending message in thread: ${error}`);
}
});
client.on("threadCreate", async (thread) => {
try {
if (thread.parentId !== process.env.FREE_SCRIPTS_CHANNEL_ID) return;
if (!thread.joinable) return;
await thread.join();

// Create the "Mark as Solved" button
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId("mark_as_solved")
.setLabel("Mark post as solved")
.setStyle(ButtonStyle.Primary),
);

// Wait for the first user message in the thread
const filter = msg => msg.threadId === thread.id && !msg.author.bot;
thread.awaitMessages({ filter, max: 1, time: 300000, errors: ["time"] }) // wait up to 5 minutes
.then(async collected => {
const botMessage = await thread.send({
content: getConstSupportGuidelinesMessage(thread.ownerId),
components: [row],
});

thread.botMessageId = botMessage.id;
})
.catch(() => {
console.warn(`No user message was sent in thread ${thread.id} after creation.`);
});


} catch (error) {
console.error(`Error sending message in thread: ${error}`);
}
});
Redboot
Redboot3w ago
what do you mean that didnt work ? You never catch a message?
Lixeiro Charmoso
Lixeiro CharmosoOP3w ago
Yes, sorry Not sure if this works thread.awaitMessages Or if i'm using correctly Even tried removing the filter, but nothing I was doing this
setTimeout(async () => {
const botMessage = await thread.send({
content: getConstSupportGuidelinesMessage(thread.ownerId),
components: [row],
});

thread.botMessageId = botMessage.id;
}, 1000); // Wait for 1 second
setTimeout(async () => {
const botMessage = await thread.send({
content: getConstSupportGuidelinesMessage(thread.ownerId),
components: [row],
});

thread.botMessageId = botMessage.id;
}, 1000); // Wait for 1 second
which works, but only when user send text messages. I really don't know how to listen to a message there
treble/luna
treble/luna2w ago
which intents do you have
souji
souji2w ago
i just wait 2s before letting it post that :kek:
Lixeiro Charmoso
Lixeiro CharmosoOP2w ago
It seems i got this working
async function waitStarterMessage(thread, maxTries = 15) {
for (let i = 0; i < maxTries; i++) {
try {
return await thread.fetchStarterMessage(); // resolves when it exists
} catch (e) {
if (e.code !== 10008) throw e; // any other error → re-throw
await new Promise(r => setTimeout(r, 1000)); // wait 1 s and retry
}
}
throw new Error("Starter message never arrived");
}
async function waitStarterMessage(thread, maxTries = 15) {
for (let i = 0; i < maxTries; i++) {
try {
return await thread.fetchStarterMessage(); // resolves when it exists
} catch (e) {
if (e.code !== 10008) throw e; // any other error → re-throw
await new Promise(r => setTimeout(r, 1000)); // wait 1 s and retry
}
}
throw new Error("Starter message never arrived");
}

Did you find this page helpful?