{"record":{"id":"9f8b9f42392e9b44","repo":"kgrzybek/modular-monolith-with-ddd","slug":"meeting-for-adding-comment-must-exist","errorCode":null,"errorMessage":"Meeting for adding comment must exist.","messagePattern":"Meeting for adding comment must exist\\.","errorType":"validation","errorClass":"InvalidCommandException","httpStatus":400,"severity":"error","filePath":"src/Modules/Meetings/Application/MeetingComments/AddMeetingComment/AddMeetingCommentCommandHandler.cs","lineNumber":38,"sourceCode":"            IMeetingRepository meetingRepository,\n            IMeetingCommentRepository meetingCommentRepository,\n            IMeetingGroupRepository meetingGroupRepository,\n            IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository,\n            IMemberContext memberContext)\n        {\n            _meetingGroupRepository = meetingGroupRepository;\n            _meetingRepository = meetingRepository;\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\n            _meetingCommentRepository = meetingCommentRepository;\n            _memberContext = memberContext;\n        }\n\n        public async Task<Guid> Handle(AddMeetingCommentCommand command, CancellationToken cancellationToken)\n        {\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(command.MeetingId));\n            if (meeting == null)\n            {\n                throw new InvalidCommandException([\"Meeting for adding comment must exist.\"]);\n            }\n\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\n\n            var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(new MeetingId(command.MeetingId));\n\n            var meetingComment = meeting.AddComment(_memberContext.MemberId, command.Comment, meetingGroup, meetingCommentingConfiguration);\n\n            await _meetingCommentRepository.AddAsync(meetingComment);\n\n            return meetingComment.Id.Value;\n        }\n    }\n}","sourceCodeStart":20,"sourceCodeEnd":52,"githubUrl":"https://github.com/kgrzybek/modular-monolith-with-ddd/blob/91c8ef24b4cb6ef558c95d8267fa07d68c7059f8/src/Modules/Meetings/Application/MeetingComments/AddMeetingComment/AddMeetingCommentCommandHandler.cs#L20-L52","documentation":"Thrown by AddMeetingCommentCommandHandler when _meetingRepository.GetByIdAsync returns null for the supplied MeetingId. Commenting requires a target meeting aggregate; if none is found the command is rejected as InvalidCommandException (HTTP 400). The meeting is also used downstream to resolve the meeting group and commenting configuration.","triggerScenarios":"Posting AddMeetingCommentCommand with a MeetingId that does not correspond to any meeting: wrong/empty Guid, meeting not yet created, meeting in a different tenant/partition, or a stale client reference.","commonSituations":"Mobile/web client retains a meeting link after the meeting was deleted; concurrency where the comment is submitted during creation; tests using a fabricated id.","solutions":["Validate the MeetingId is a non-empty, existing meeting before allowing the user to comment.","Refresh the client's meeting list so stale ids are not submitted.","In the controller, check meeting existence via a query and return 404 instead of dispatching.","Handle InvalidCommandException at the API boundary and return 400/404."],"exampleFix":"// before\nvar commentId = await _commandDispatcher.SendAsync(new AddMeetingCommentCommand(meetingId, text));\n\n// after\nvar meeting = await _meetingQueries.GetMeetingAsync(meetingId);\nif (meeting is null) return NotFound(\"Meeting not found.\");\nvar commentId = await _commandDispatcher.SendAsync(new AddMeetingCommentCommand(meetingId, text));","handlingStrategy":"validation","validationCode":"var meeting = await _meetingQueries.GetMeetingAsync(meetingId);\nif (meeting is null) return NotFound(\"Meeting not found.\");\nvar id = await _commandDispatcher.SendAsync(new AddMeetingCommentCommand(meetingId, text));","typeGuard":"public static bool IsValidMeetingId(AddMeetingCommentCommand c) =>\n    c.MeetingId != Guid.Empty && !string.IsNullOrWhiteSpace(c.Comment);","tryCatchPattern":"try { await _commandDispatcher.SendAsync(cmd); }\ncatch (InvalidCommandException ex) when (ex.Errors.Any(m => m.Contains(\"must exist\")))\n{ return NotFound(new { errors = ex.Errors }); }","preventionTips":["Refresh the client's meeting list so deleted meetings are not referenced.","Disable the comment box when the meeting is not loaded.","Validate non-empty Guid and non-empty comment client-side."],"tags":["meetings","comments","not-found","invalid-command-exception","command-handler"],"backgroundTag":null,"analyzedSha":"91c8ef24b4cb6ef558c95d8267fa07d68c7059f8","analyzedAt":"2026-08-13T17:18:16.571Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}