fullstackhero/dotnet-starter-kit · error · ArgumentException

Cannot start a DM with yourself.

Error message

Cannot start a DM with yourself.

What it means

ChatChannel.CreateDirect validates that the two DM participants differ; passing the same user id as both sides throws ArgumentException("Cannot start a DM with yourself.", nameof(userBId)). The domain factory enforces a DM is always between two distinct users.

Solutions

  1. Before calling, guard: if (currentUserId == targetUserId) don't create a DM.
  2. Hide/disable the DM action on the user's own profile in the UI.
  3. If self-chat is a requirement, model it as a saved-messages channel rather than CreateDirect.
  4. In the endpoint, derive the caller from the token and the peer from the route so they can't be conflated.

Example fix

// before
var channel = ChatChannel.CreateDirect(currentUserId, targetUserId);
// after
if (currentUserId == targetUserId)
    return Results.BadRequest("Cannot start a DM with yourself.");
var channel = ChatChannel.CreateDirect(currentUserId, targetUserId);
Defensive patterns

Strategy: validation

Validate before calling

// before calling the factory
if (string.IsNullOrWhiteSpace(userAId) || string.IsNullOrWhiteSpace(userBId))
    throw new ValidationException("Both user ids are required");
if (userAId == userBId)
    throw new ValidationException("Cannot start a DM with yourself");

Type guard

bool CanCreateDm(string me, string peer) =>
    !string.IsNullOrWhiteSpace(me) && !string.IsNullOrWhiteSpace(peer) &&
    !string.Equals(me, peer, StringComparison.Ordinal);

Try / catch

try { var c = ChatChannel.CreateDirect(a, b); }
catch (ArgumentException ex) when (ex.ParamName == nameof(userBId)) { return Results.BadRequest(ex.Message); }

Prevention

When it happens

Trigger: CreateDirect(userAId, userBId) invoked with string.Equals(userAId, userBId, Ordinal) true — e.g. the caller passes the authenticated user's id as both arguments, or the 'target user' selection defaults to self.

Common situations: UI 'message this user' button rendered on the current user's own profile; endpoint taking a userId from the route and accidentally using the token's sub as the peer; tests using a single seeded user id for both sides.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/f118c3be76bbaac1. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Chat/Modules.Chat/Domain/ChatChannel.cs:95

            Slug = Slugify(name),
            Description = description?.Trim(),
            IsPrivate = isPrivate,
            CreatedByUserId = creatorUserId,
            CreatedAtUtc = DateTime.UtcNow,
        };
        c._members.Add(ChannelMember.Create(c.Id, creatorUserId, ChannelMemberRole.Admin));
        c.AddDomainEvent(DomainEvent.Create((id, ts) =>
            new ChannelCreatedDomainEvent(c.Id, c.Type, c.Name, creatorUserId, id, ts)));
        return c;
    }

    public static ChatChannel CreateDirect(string userAId, string userBId)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(userAId);
        ArgumentException.ThrowIfNullOrWhiteSpace(userBId);
        if (string.Equals(userAId, userBId, StringComparison.Ordinal))
        {
            throw new ArgumentException("Cannot start a DM with yourself.", nameof(userBId));
        }

        var (lo, hi) = string.CompareOrdinal(userAId, userBId) < 0 ? (userAId, userBId) : (userBId, userAId);
        var c = new ChatChannel
        {
            Id = Guid.CreateVersion7(),
            Type = ChannelType.DirectMessage,
            IsPrivate = true,
            DirectKey = $"{lo}:{hi}",
            CreatedByUserId = userAId,
            CreatedAtUtc = DateTime.UtcNow,
        };
        c._members.Add(ChannelMember.Create(c.Id, userAId, ChannelMemberRole.Member));
        c._members.Add(ChannelMember.Create(c.Id, userBId, ChannelMemberRole.Member));
        c.AddDomainEvent(DomainEvent.Create((id, ts) =>
            new ChannelCreatedDomainEvent(c.Id, c.Type, null, userAId, id, ts)));
        return c;
    }

View on GitHub (pinned to 3f2959e683)