{"record":{"id":"4f388a5b57cca3b9","repo":"fullstackhero/dotnet-starter-kit","slug":"channelid-is-required","errorCode":null,"errorMessage":"ChannelId is required.","messagePattern":"ChannelId is required\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Modules/Chat/Modules.Chat/Domain/Message.cs","lineNumber":45,"sourceCode":"    private readonly List<MessageMention> _mentions = [];\n    public IReadOnlyList<MessageMention> Mentions => _mentions;\n\n    private readonly List<MessageReaction> _reactions = [];\n    public IReadOnlyList<MessageReaction> Reactions => _reactions;\n\n    private Message() { }\n\n    public static Message Create(\n        Guid channelId,\n        string authorUserId,\n        string? body,\n        Guid? parentMessageId = null,\n        IReadOnlyList<ParsedMention>? mentions = null)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(authorUserId);\n        if (channelId == Guid.Empty)\n        {\n            throw new ArgumentException(\"ChannelId is required.\", nameof(channelId));\n        }\n\n        // Body is optional here; the SendMessage validator enforces \"body OR >=1 attachment\"\n        // (attachments attach AFTER Create via AddAttachment).\n        var trimmed = string.IsNullOrWhiteSpace(body) ? null : body.Trim();\n\n        var m = new Message\n        {\n            Id = Guid.CreateVersion7(),\n            ChannelId = channelId,\n            AuthorUserId = authorUserId,\n            Body = trimmed,\n            ParentMessageId = parentMessageId,\n            CreatedAtUtc = DateTime.UtcNow,\n        };\n        if (mentions is not null)\n        {\n            foreach (var pm in mentions)","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Chat/Modules.Chat/Domain/Message.cs#L27-L63","documentation":"Message.Create validates that a message is always attached to a channel: a Guid.Empty channelId fails ArgumentException with the parameter name. Since Guid is a value type, null is impossible — 'unset' is represented as Guid.Empty and explicitly rejected. This is a missing-required-argument guard at the domain factory.","triggerScenarios":"Calling Message.Create(channelId: Guid.Empty, ...) — typically an uninitialized Guid field/property, a record deserialized from a payload where channelId was missing/default, or a handler that never assigned the route/channel parameter.","commonSituations":"new Guid() instead of Guid.NewGuid(); request DTO with missing channelId defaulting to Guid.Empty; mapping bugs where the channel id is copied from the wrong source; tests constructing messages without an id.","solutions":["Pass a valid non-empty channel id loaded from an existing ChatChannel (channel.Id) into Message.Create.","Guard earlier in the pipeline: FluentValidation RuleFor(x => x.ChannelId).NotEmpty() on the command so it never reaches the domain.","Fix 'new Guid()' usages / missing mapping that produce Guid.Empty.","If channelId comes from a route/body, return 400 at the binding/validation layer with a clear message."],"exampleFix":"// before\nvar message = Message.Create(Guid.Empty, authorUserId, body);\n// after\nRuleFor(x => x.ChannelId).NotEmpty();\n...\nvar channel = await db.Channels.FindAsync([command.ChannelId], ct)\n    ?? throw new NotFoundException(nameof(ChatChannel), command.ChannelId);\nvar message = Message.Create(channel.Id, command.AuthorUserId, command.Body);","handlingStrategy":"validation","validationCode":"public static bool HasChannelId(Guid channelId) => channelId != Guid.Empty;","typeGuard":"if (command.ChannelId == Guid.Empty) throw new ValidationException(\"ChannelId is required.\");","tryCatchPattern":"try { var m = Message.Create(channelId, authorId, body); } catch (ArgumentException ex) when (ex.ParamName == \"channelId\") { throw new ValidationException(\"ChannelId is required.\"); }","preventionTips":["Add RuleFor(x => x.ChannelId).NotEmpty() to the command validator","Avoid new Guid(); assign ids at construction time","Verify mapping of channelId from route/body into the command","Resolve the channel entity and use its Id when creating messages"],"tags":["domain","chat","argument","guid","validation"],"backgroundTag":"missing-required-argument","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"}