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

{validator error messages}

Error message

{validator error messages}

What it means

Thrown by the Payments module ValidationCommandHandlerDecorator, which wraps every command handler. It runs all registered FluentValidation validators for the command T, collects every ValidationFailure.ErrorMessage, and if any exist throws InvalidCommandException(errors). The literal message '{validator error messages}' is a placeholder: the real messages come from the command's validators.

Source

Thrown at src/Modules/Payments/Infrastructure/Configuration/Processing/ValidationCommandHandlerDecorator.cs:32

        public ValidationCommandHandlerDecorator(
            IList<IValidator<T>> validators,
            ICommandHandler<T> decorated)
        {
            this._validators = validators;
            _decorated = decorated;
        }

        public async Task Handle(T command, CancellationToken cancellationToken)
        {
            var errors = _validators
                .Select(v => v.Validate(command))
                .SelectMany(result => result.Errors)
                .Where(error => error != null)
                .ToList();

            if (errors.Any())
            {
                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());
            }

            await _decorated.Handle(command, cancellationToken);
        }
    }
}

View on GitHub (pinned to 91c8ef24b4)

Solutions

  1. Inspect ex.Errors to see exactly which validators failed and which properties.
  2. Fix the offending command property to satisfy the validator (length, format, required-ness, allowed values).
  3. Run the same FluentValidation validators on the client/API layer before dispatching.
  4. Register/adjust validators if a legitimate value is being rejected.

Example fix

// before
await _commandDispatcher.SendAsync(new ChangePriceListItemAttributesCommand(itemId, "", "", "", -1, ""));

// after
await _commandDispatcher.SendAsync(new ChangePriceListItemAttributesCommand(itemId, "PL", "MONTHLY", "PRO", 19.99m, "PLN"));
Defensive patterns

Strategy: validation

Validate before calling

var validator = new ChangePriceListItemAttributesCommandValidator();
var result = await validator.ValidateAsync(cmd);
if (!result.IsValid) return BadRequest(result.Errors.Select(e => e.ErrorMessage));
await _commandDispatcher.SendAsync(cmd);

Try / catch

try { await _commandDispatcher.SendAsync(cmd); }
catch (InvalidCommandException ex)
{ return BadRequest(new { errors = ex.Errors }); }

Prevention

When it happens

Trigger: Sending any Payments command whose properties fail a registered FluentValidation validator: null/empty required fields, strings exceeding length, invalid enum codes, negative money values, malformed Guids, etc.

Common situations: Client omits a required field; enum code not in the allowed catalog; money currency empty; integration test constructs a command by hand and skips required values.

Related errors


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