{"record":{"id":"7a369a91d7839b8a","repo":"LuckyPennySoftware/MediatR","slug":"notification-does-not-implement-inotification","errorCode":null,"errorMessage":"notification does not implement $INotification","messagePattern":"notification does not implement \\$INotification","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/MediatR/Mediator.cs","lineNumber":137,"sourceCode":"    }\r\n\r\n    public Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)\r\n        where TNotification : INotification\r\n    {\r\n        if (notification == null)\r\n        {\r\n            throw new ArgumentNullException(nameof(notification));\r\n        }\r\n\r\n        return PublishNotification(notification, cancellationToken);\r\n    }\r\n\r\n    public Task Publish(object notification, CancellationToken cancellationToken = default) =>\r\n        notification switch\r\n        {\r\n            null => throw new ArgumentNullException(nameof(notification)),\r\n            INotification instance => PublishNotification(instance, cancellationToken),\r\n            _ => throw new ArgumentException($\"{nameof(notification)} does not implement ${nameof(INotification)}\")\r\n        };\r\n\r\n    /// <summary>\r\n    /// Override in a derived class to control how the tasks are awaited. By default the implementation calls the <see cref=\"INotificationPublisher\"/>.\r\n    /// </summary>\r\n    /// <param name=\"handlerExecutors\">Enumerable of tasks representing invoking each notification handler</param>\r\n    /// <param name=\"notification\">The notification being published</param>\r\n    /// <param name=\"cancellationToken\">The cancellation token</param>\r\n    /// <returns>A task representing invoking all handlers</returns>\r\n    protected virtual Task PublishCore(IEnumerable<NotificationHandlerExecutor> handlerExecutors, INotification notification, CancellationToken cancellationToken) \r\n        => _publisher.Publish(handlerExecutors, notification, cancellationToken);\r\n\r\n    private Task PublishNotification(INotification notification, CancellationToken cancellationToken = default)\r\n    {\r\n        var handler = _notificationHandlers.GetOrAdd(notification.GetType(), static notificationType =>\r\n        {\r\n            var wrapperType = typeof(NotificationHandlerWrapperImpl<>).MakeGenericType(notificationType);\r\n            var wrapper = Activator.CreateInstance(wrapperType) ?? throw new InvalidOperationException($\"Could not create wrapper for type {notificationType}\");\r","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/LuckyPennySoftware/MediatR/blob/916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5/src/MediatR/Mediator.cs#L119-L155","documentation":"The non-generic Publish(object) overload pattern-matches the payload: nulls throw ArgumentNullException, INotification instances are forwarded, and anything else throws ArgumentException. Note the message text itself contains a literal bug — the source reads `$\"{nameof(notification)} does not implement ${nameof(INotification)}\"`, so the rendered text is `notification does not implement $INotification` (a stray `$` before the interface name).","triggerScenarios":"Calling mediator.Publish(someObject) where someObject does not implement INotification (e.g. a plain DTO, an event from another library, or a request mistakenly sent as a notification).","commonSituations":"Cross-system dispatch that boxes payloads as object and passes the wrong type; reusing a request type as a notification without implementing INotification; legacy payloads not yet migrated to the notification contract.","solutions":["Make the type implement INotification: `public record FooHappened : INotification`.","If the payload is actually a request, call Send instead of Publish.","Use the generic Publish<TNotification> overload where TNotification : INotification to catch mismatches at compile time."],"exampleFix":"// before\npublic class OrderShipped { public Guid Id; }\nmediator.Publish(orderShipped); // ArgumentException\n// after\npublic record OrderShipped(Guid Id) : INotification;\nmediator.Publish(orderShipped);","handlingStrategy":"type-guard","validationCode":"if (notification is not INotification)\n    throw new ArgumentException($\"{notification?.GetType().Name ?? \"null\"} is not an INotification.\", nameof(notification));","typeGuard":"static bool IsNotification(object o) => o is INotification;","tryCatchPattern":null,"preventionTips":["Use the generic Publish<TNotification>() where TNotification : INotification overload.","Mark event types with INotification at definition.","Do not pass request objects to Publish."],"tags":["mediator","publish","inotification","type-validation","message-bug"],"backgroundTag":null,"analyzedSha":"916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5","analyzedAt":"2026-08-13T17:57:04.476Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}