{"record":{"id":"f118c3be76bbaac1","repo":"fullstackhero/dotnet-starter-kit","slug":"cannot-start-a-dm-with-yourself","errorCode":null,"errorMessage":"Cannot start a DM with yourself.","messagePattern":"Cannot start a DM with yourself\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Modules/Chat/Modules.Chat/Domain/ChatChannel.cs","lineNumber":95,"sourceCode":"            Slug = Slugify(name),\n            Description = description?.Trim(),\n            IsPrivate = isPrivate,\n            CreatedByUserId = creatorUserId,\n            CreatedAtUtc = DateTime.UtcNow,\n        };\n        c._members.Add(ChannelMember.Create(c.Id, creatorUserId, ChannelMemberRole.Admin));\n        c.AddDomainEvent(DomainEvent.Create((id, ts) =>\n            new ChannelCreatedDomainEvent(c.Id, c.Type, c.Name, creatorUserId, id, ts)));\n        return c;\n    }\n\n    public static ChatChannel CreateDirect(string userAId, string userBId)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(userAId);\n        ArgumentException.ThrowIfNullOrWhiteSpace(userBId);\n        if (string.Equals(userAId, userBId, StringComparison.Ordinal))\n        {\n            throw new ArgumentException(\"Cannot start a DM with yourself.\", nameof(userBId));\n        }\n\n        var (lo, hi) = string.CompareOrdinal(userAId, userBId) < 0 ? (userAId, userBId) : (userBId, userAId);\n        var c = new ChatChannel\n        {\n            Id = Guid.CreateVersion7(),\n            Type = ChannelType.DirectMessage,\n            IsPrivate = true,\n            DirectKey = $\"{lo}:{hi}\",\n            CreatedByUserId = userAId,\n            CreatedAtUtc = DateTime.UtcNow,\n        };\n        c._members.Add(ChannelMember.Create(c.Id, userAId, ChannelMemberRole.Member));\n        c._members.Add(ChannelMember.Create(c.Id, userBId, ChannelMemberRole.Member));\n        c.AddDomainEvent(DomainEvent.Create((id, ts) =>\n            new ChannelCreatedDomainEvent(c.Id, c.Type, null, userAId, id, ts)));\n        return c;\n    }","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Chat/Modules.Chat/Domain/ChatChannel.cs#L77-L113","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvar channel = ChatChannel.CreateDirect(currentUserId, targetUserId);\n// after\nif (currentUserId == targetUserId)\n    return Results.BadRequest(\"Cannot start a DM with yourself.\");\nvar channel = ChatChannel.CreateDirect(currentUserId, targetUserId);","handlingStrategy":"validation","validationCode":"// before calling the factory\nif (string.IsNullOrWhiteSpace(userAId) || string.IsNullOrWhiteSpace(userBId))\n    throw new ValidationException(\"Both user ids are required\");\nif (userAId == userBId)\n    throw new ValidationException(\"Cannot start a DM with yourself\");","typeGuard":"bool CanCreateDm(string me, string peer) =>\n    !string.IsNullOrWhiteSpace(me) && !string.IsNullOrWhiteSpace(peer) &&\n    !string.Equals(me, peer, StringComparison.Ordinal);","tryCatchPattern":"try { var c = ChatChannel.CreateDirect(a, b); }\ncatch (ArgumentException ex) when (ex.ParamName == nameof(userBId)) { return Results.BadRequest(ex.Message); }","preventionTips":["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."],"tags":["chat","argument","domain","dm","self-reference"],"backgroundTag":"invalid-argument-value","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}