kgrzybek/modular-monolith-with-ddd · error · InvalidCommandException
To create reply the comment must exist.
Error message
To create reply the comment must exist.
What it means
Thrown by AddReplyToMeetingCommentCommandHandler when GetByIdAsync for the InReplyToCommentId returns null. Replies require a parent comment; a missing parent rejects the command with InvalidCommandException (HTTP 400). The parent comment is also used to resolve the meeting, group, and commenting configuration.
Source
Thrown at src/Modules/Meetings/Application/MeetingComments/AddMeetingCommentReply/AddReplyToMeetingCommentCommandHandler.cs:33
private readonly IMeetingGroupRepository _meetingGroupRepository;
private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;
private readonly IMemberContext _memberContext;
internal AddReplyToMeetingCommentCommandHandler(IMeetingCommentRepository meetingCommentRepository, IMeetingRepository meetingRepository, IMeetingGroupRepository meetingGroupRepository, IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository, IMemberContext memberContext)
{
_meetingCommentRepository = meetingCommentRepository;
_meetingRepository = meetingRepository;
_meetingGroupRepository = meetingGroupRepository;
_meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;
_memberContext = memberContext;
}
public async Task<Guid> Handle(AddReplyToMeetingCommentCommand command, CancellationToken cancellationToken)
{
var meetingComment = await _meetingCommentRepository.GetByIdAsync(new MeetingCommentId(command.InReplyToCommentId));
if (meetingComment == null)
{
throw new InvalidCommandException(["To create reply the comment must exist."]);
}
var meeting = await _meetingRepository.GetByIdAsync(meetingComment.GetMeetingId());
var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());
var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(meetingComment.GetMeetingId());
var replyToComment = meetingComment.Reply(_memberContext.MemberId, command.Reply, meetingGroup, meetingCommentingConfiguration);
await _meetingCommentRepository.AddAsync(replyToComment);
return replyToComment.Id.Value;
}
}
}View on GitHub (pinned to 91c8ef24b4)
Solutions
- Verify InReplyToCommentId exists and is still available before allowing reply.
- Refresh the thread on the client so deleted parents are removed.
- Pre-check parent existence in the controller and return 404.
- Catch InvalidCommandException at the API boundary and map to 400/404.
Example fix
// before
var replyId = await _commandDispatcher.SendAsync(new AddReplyToMeetingCommentCommand(parentCommentId, text));
// after
var parent = await _meetingQueries.GetCommentAsync(parentCommentId);
if (parent is null) return NotFound("Parent comment not found.");
var replyId = await _commandDispatcher.SendAsync(new AddReplyToMeetingCommentCommand(parentCommentId, text)); Defensive patterns
Strategy: validation
Validate before calling
var parent = await _meetingQueries.GetCommentAsync(parentCommentId);
if (parent is null) return NotFound("Parent comment not found.");
var replyId = await _commandDispatcher.SendAsync(new AddReplyToMeetingCommentCommand(parentCommentId, text)); Type guard
public static bool IsValidReplyCommand(AddReplyToMeetingCommentCommand c) =>
c.InReplyToCommentId != Guid.Empty && !string.IsNullOrWhiteSpace(c.Reply); 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
- Re-fetch the thread before allowing a reply to drop stale parents.
- Validate a non-empty parent id and non-empty reply text client-side.
- Disable the reply box when the parent is no longer in the rendered thread.
When it happens
Trigger: Dispatching AddReplyToMeetingCommentCommand with an InReplyToCommentId that has no comment: deleted parent, wrong id, or passing a reply id whose own thread was removed.
Common situations: Threaded UI renders a cached parent that was since deleted; client posts a reply to a comment id pulled from a stale notification.
Related errors
- Meeting for adding comment must exist.
- To add like the comment must exist.
- Meeting comment for editing must exist.
- Meeting comment for removing must exist.
- Meeting comment like for removing must exist.
AI-assisted analysis of kgrzybek/modular-monolith-with-ddd@91c8ef24b4 (2026-08-13).
Data as JSON: /api/errors/c7ea118bb1c625d6.
Report an issue: GitHub.