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
- Before calling, guard: if (currentUserId == targetUserId) don't create a DM.
- Hide/disable the DM action on the user's own profile in the UI.
- If self-chat is a requirement, model it as a saved-messages channel rather than CreateDirect.
- 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
- Hide DM buttons on the current user's own profile.
- Keep caller id and peer id from separate sources (token vs route) to avoid conflation.
- Add a unit test asserting CreateDirect(x, x) throws.
- If self-chat is needed, build a dedicated saved-messages channel type.
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
- Group DM requires at least 3 distinct members.
- All user ids must be non-empty.
- ChannelId is required.
- Only named Channels can be renamed.
- Only named Channels can change privacy.
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)