{"record":{"id":"5b8067ef9d760912","repo":"kgrzybek/modular-monolith-with-ddd","slug":"validator-error-messages-5b8067","errorCode":null,"errorMessage":"{validator error messages}","messagePattern":"\\{validator error messages\\}","errorType":"validation","errorClass":"InvalidCommandException","httpStatus":400,"severity":"warning","filePath":"src/Modules/Payments/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs","lineNumber":32,"sourceCode":"        public ValidationCommandHandlerWithResultDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T, TResult> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            return _decorated.Handle(command, cancellationToken);\n        }\n    }\n}","sourceCodeStart":14,"sourceCodeEnd":38,"githubUrl":"https://github.com/kgrzybek/modular-monolith-with-ddd/blob/91c8ef24b4cb6ef558c95d8267fa07d68c7059f8/src/Modules/Payments/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs#L14-L38","documentation":"Thrown by the Payments module ValidationCommandHandlerWithResultDecorator, the TResult-returning counterpart of the validation decorator. It runs all FluentValidation validators for command T, aggregates the ErrorMessages, and throws InvalidCommandException(errors) when any validation fails. The placeholder '{validator error messages}' is replaced by the actual validator messages at throw time.","triggerScenarios":"Sending any Payments command that returns a result (e.g. BuySubscriptionRenewalCommand returns Guid) with properties that fail a registered validator.","commonSituations":"Same as the void decorator but on result-returning commands: missing required fields, invalid enum codes, malformed ids, bad money values.","solutions":["Read ex.Errors to identify the failing validators and properties.","Correct the command values to satisfy validation.","Pre-validate on the client/API layer using the same validators.","Adjust validator rules if a valid business value is being rejected."],"exampleFix":"// before\nvar id = await _commandDispatcher.SendAsync(new BuySubscriptionRenewalCommand(Guid.Empty, \"\", \"\", 0, \"\"));\n\n// after\nvar id = await _commandDispatcher.SendAsync(new BuySubscriptionRenewalCommand(subscriptionId, \"MONTHLY\", \"PL\", 49.99m, \"PLN\"));","handlingStrategy":"validation","validationCode":"var validator = new BuySubscriptionRenewalCommandValidator();\nvar result = await validator.ValidateAsync(cmd);\nif (!result.IsValid) return BadRequest(result.Errors.Select(e => e.ErrorMessage));\nvar id = await _commandDispatcher.SendAsync(cmd);","typeGuard":null,"tryCatchPattern":"try { var id = await _commandDispatcher.SendAsync(cmd); }\ncatch (InvalidCommandException ex)\n{ return BadRequest(new { errors = ex.Errors }); }","preventionTips":["Pre-validate result-returning commands with their validators client-side.","Inspect ex.Errors for the offending properties.","Ensure validators cover enum codes and money format."],"tags":["payments","validation","fluentvalidation","command-handler","invalid-command-exception","decorator"],"backgroundTag":null,"analyzedSha":"91c8ef24b4cb6ef558c95d8267fa07d68c7059f8","analyzedAt":"2026-08-13T17:18:16.571Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}