Tyrrrz/DiscordChatExporter · error · DiscordChatExporterException

Channel '{request.Channel.Name}' of guild '{request.Guild.Na

Error message

Channel '{request.Channel.Name}' of guild '{request.Guild.Name}' is a forum and cannot be exported directly. You need to pull its threads and export them individually.

What it means

Thrown as DiscordChatExporterException by ChannelExporter.ExportChannelAsync when the target channel's Kind is GuildForum. Forum channels hold no direct messages — only a collection of threads — so exporting them directly would produce nothing. The tool tells the user to export the forum's threads individually instead.

Source

Thrown at DiscordChatExporter.Core/Exporting/ChannelExporter.cs:22

using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Core.Exceptions;
using Gress;

namespace DiscordChatExporter.Core.Exporting;

public class ChannelExporter(DiscordClient discord)
{
    public async ValueTask ExportChannelAsync(
        ExportRequest request,
        IProgress<Percentage>? progress = null,
        CancellationToken cancellationToken = default
    )
    {
        // Forum channels don't have messages, they are just a list of threads
        if (request.Channel.Kind == ChannelKind.GuildForum)
        {
            throw new DiscordChatExporterException(
                $"Channel '{request.Channel.Name}' "
                    + $"of guild '{request.Guild.Name}' "
                    + $"is a forum and cannot be exported directly. "
                    + "You need to pull its threads and export them individually."
            );
        }

        // Build context
        var context = new ExportContext(discord, request);
        await context.PopulateChannelsAndRolesAsync(cancellationToken);

        // Initialize the exporter before further checks to ensure the file is created even if
        // an exception is thrown after this point.
        await using var messageExporter = new MessageExporter(context);

        // Check if the channel is empty
        if (request.Channel.IsEmpty)
        {

View on GitHub (pinned to f6865c8216)

Solutions

  1. Use exportall/exportguild with --include-threads set to Archived, Unarchived, or All so forum threads are pulled and exported individually.
  2. List the forum's threads and export each thread ID with exportchat.
  3. Exclude forum channels from a batch export if you do not want their threads.

Example fix

// before
dotnet run -- exportchat -c <forum-channel-id> -t <token>
// after
dotnet run -- exportall -c <forum-channel-id> -t <token> --include-threads all
Defensive patterns

Strategy: validation

Validate before calling

var channel = await discord.GetChannelAsync(channelId, ct);
if (channel.Kind == ChannelKind.GuildForum)
    throw new InvalidOperationException("Use exportall --include-threads to export a forum's threads.");

Type guard

static bool IsForum(Channel c) => c.Kind == ChannelKind.GuildForum;

Try / catch

try { await exporter.ExportChannelAsync(req, progress, ct); }
catch (DiscordChatExporterException ex) when (ex.Message.Contains("forum"))
{
    logger.LogInformation("{Channel} is a forum — rerun with --include-threads", req.Channel.Name);
}

Prevention

When it happens

Trigger: ExportChannelAsync is called with a request whose request.Channel.Kind == ChannelKind.GuildForum (ChannelExporter.cs:21). This happens when exportchat is pointed at a forum channel ID.

Common situations: User grabs a forum channel ID and runs exportchat on it; a guild-level exportall flattens forum channels into direct export calls; forum channel reused as a regular channel after a type change.

Related errors


AI-assisted analysis of Tyrrrz/DiscordChatExporter@f6865c8216 (2026-08-13). Data as JSON: /api/errors/d50069be9f5dfa48. Report an issue: GitHub.