kgrzybek/modular-monolith-with-ddd · error · InvalidCommandException

To add like the comment must exist.

Error message

To add like the comment must exist.

What it means

Thrown by AddMeetingCommentLikeCommandHandler when _meetingCommentRepository.GetByIdAsync returns null for the supplied MeetingCommentId. A like must attach to an existing comment, so a missing comment aborts the command with InvalidCommandException (HTTP 400).

Source

Thrown at src/Modules/Meetings/Application/MeetingComments/AddMeetingCommentLike/AddMeetingCommentLikeCommandHandler.cs:35

        public AddMeetingCommentLikeCommandHandler(
            IMeetingCommentRepository meetingCommentRepository,
            IMeetingMemberCommentLikesRepository meetingMemberCommentLikesRepository,
            IMemberContext memberContext,
            ISqlConnectionFactory sqlConnectionFactory)
        {
            _meetingCommentRepository = meetingCommentRepository;
            _memberContext = memberContext;
            _sqlConnectionFactory = sqlConnectionFactory;
            _meetingMemberCommentLikesRepository = meetingMemberCommentLikesRepository;
        }

        public async Task Handle(AddMeetingCommentLikeCommand request, CancellationToken cancellationToken)
        {
            var meetingComment = await _meetingCommentRepository.GetByIdAsync(new MeetingCommentId(request.MeetingCommentId));
            if (meetingComment == null)
            {
                throw new InvalidCommandException(["To add like the comment must exist."]);
            }

            var connection = _sqlConnectionFactory.GetOpenConnection();
            var likerMeetingGroupMemberData = await MembersQueryHelper.GetMeetingGroupMember(_memberContext.MemberId, meetingComment.GetMeetingId(), connection);

            var meetingMemeberCommentLikesCount = await _meetingMemberCommentLikesRepository.CountMemberCommentLikesAsync(
                    _memberContext.MemberId,
                    new MeetingCommentId(request.MeetingCommentId));

            var like = meetingComment.Like(_memberContext.MemberId, likerMeetingGroupMemberData, meetingMemeberCommentLikesCount);

            await _meetingMemberCommentLikesRepository.AddAsync(like);
        }
    }
}

View on GitHub (pinned to 91c8ef24b4)

Solutions

  1. Confirm the MeetingCommentId refers to an existing, non-removed comment.
  2. Ensure the client sends the comment id, not the meeting or reply id.
  3. Pre-check comment existence in the controller and return 404.
  4. Map InvalidCommandException to a 400/404 at the API boundary.

Example fix

// before
await _commandDispatcher.SendAsync(new AddMeetingCommentLikeCommand(commentId));

// after
var comment = await _meetingQueries.GetCommentAsync(commentId);
if (comment is null) return NotFound("Comment not found.");
await _commandDispatcher.SendAsync(new AddMeetingCommentLikeCommand(commentId));
Defensive patterns

Strategy: validation

Validate before calling

var comment = await _meetingQueries.GetCommentAsync(commentId);
if (comment is null) return NotFound("Comment not found.");
await _commandDispatcher.SendAsync(new AddMeetingCommentLikeCommand(commentId));

Type guard

public static bool IsValidCommentId(AddMeetingCommentLikeCommand c) =>
    c.MeetingCommentId != Guid.Empty;

Try / catch

try { await _commandDispatcher.SendAsync(cmd); }
catch (InvalidCommandException ex) when (ex.Errors.Any(m => m.Contains("must exist")))
{ return NotFound(new { errors = ex.Errors }); }

Prevention

When it happens

Trigger: Dispatching AddMeetingCommentLikeCommand for a comment id that does not exist: wrong Guid, comment was removed, reply-vs-comment id confusion, or a stale client reference.

Common situations: User likes a comment that was just deleted by its author; race between render and like; client passes the meeting id instead of the comment id.

Related errors


AI-assisted analysis of kgrzybek/modular-monolith-with-ddd@91c8ef24b4 (2026-08-13). Data as JSON: /api/errors/8075e7c0af7bf323. Report an issue: GitHub.