Troubleshooting
Checklists, diagnostics reference, and FAQ for Pragmatic.Messaging.
Handler Not Invoked
Section titled “Handler Not Invoked”- Class has
[MessageHandler]attribute - Class implements
IMessageHandler<T>(not just the method signature) - Class is
partial(for[LoggerMessage]integration) - Message type
Tmatches the event being published - Module is referenced by the host project (SG runs per-project)
-
dotnet clean && dotnet build(stale SG cache)
Outbox Messages Not Delivered
Section titled “Outbox Messages Not Delivered”-
EnableOutbox()called inUseMessaging()config - DbContext has
[EnableOutbox]attribute -
SagaEntityTypeConfiguration/OutboxEntityTypeConfigurationapplied to DbContext -
OutboxDeliveryServiceis running (check logs forPragmatic.Messaging.OutboxDeliveryService) -
IMessageTypeRegistrycan deserialize the message type (check_Infra.Messaging.TypeRegistry.g.cs) - Database has
__OutboxMessagestable (migration applied)
Retry Not Working
Section titled “Retry Not Working”-
[Retry]attribute is on the handler class (not the method) -
MaxAttempts > 0(PRAG0802 if zero) - Exception is NOT
OperationCanceledException(excluded from retry) - Check generated
_Pipeline.g.csforfor (var __attemptloop - Verify metrics:
pragmatic.messaging.retry_attemptscounter
Circuit Breaker Always Open
Section titled “Circuit Breaker Always Open”- Check
FailureThreshold— lower values trip faster -
BreakDurationSecondscontrols how long the circuit stays open - Circuit state is per-handler-type (static) — resets on success
- After
BreakDurationSeconds, next call is “half-open” (if it succeeds, circuit closes)
Saga Not Progressing
Section titled “Saga Not Progressing”- Saga class has
[Saga<TState>]attribute - Exactly one method has
[SagaStart](PRAG0814 if missing) -
[InState]values match enum members (check PRAG0810 for inconsistencies) - Handler methods return the next action to dispatch (not null)
- Repository is registered (
EnableSagas()orEnableSagaPersistence()) - Correlation ID is consistent across all events in the workflow
Batch Progress at 0%
Section titled “Batch Progress at 0%”- Handler calls
BatchTracker.ReportSuccessAsync(context, store)after processing - Handler calls
BatchTracker.ReportFailureAsync(context, store)in catch block -
EnableBatchProcessing()called inUseMessaging()config -
BatchDispatcherpublished items with batch headers (checkcontext.Headers["batch.id"])
Diagnostics Reference
Section titled “Diagnostics Reference”Handler Diagnostics
Section titled “Handler Diagnostics”| ID | Severity | Message | Fix |
|---|---|---|---|
| PRAG0800 | Error | [MessageHandler] on non-IMessageHandler<T> | Add IMessageHandler<T> interface |
| PRAG0801 | Warning | Handler not partial | Add partial keyword |
| PRAG0802 | Error | [Retry] with MaxAttempts <= 0 | Set positive value |
| PRAG0803 | Error | [MessageMiddleware] on non-IMessageMiddleware | Add IMessageMiddleware interface |
Saga Diagnostics
Section titled “Saga Diagnostics”| ID | Severity | Message | Fix |
|---|---|---|---|
| PRAG0810 | Error | Inconsistent state transition | Fix [InState]/NextState graph |
| PRAG0811 | Info | State has no handler | Expected for terminal states (Completed, Cancelled) |
| PRAG0812 | Warning | Unreachable states | Add transitions from [SagaStart] |
| PRAG0813 | Error | [Saga<T>] where T is not enum | Use enum type parameter |
| PRAG0814 | Error | Saga without [SagaStart] | Add [SagaStart] to entry method |
Cross-Boundary Diagnostics
Section titled “Cross-Boundary Diagnostics”| ID | Severity | Message | Fix |
|---|---|---|---|
| PRAG0815 | Warning | Handler consumes cross-boundary without [DependsOn] | Add dependency |
| PRAG0816 | Warning | Event type has no consumers | Add handler or remove event |
| PRAG0817 | Error | Queue name collision | Rename handler |
| PRAG0818 | Warning | Cross-boundary without outbox | Add [EnableOutbox] |
Outbox Diagnostics
Section titled “Outbox Diagnostics”| ID | Severity | Message | Fix |
|---|---|---|---|
| PRAG0830 | Error | [EnableOutbox] on non-DbContext | Apply to DbContext subclass |
| PRAG0831 | Error | Missing Pragmatic.Messaging.EFCore reference | Add NuGet reference |
How do I test handlers without a real transport?
Section titled “How do I test handlers without a real transport?”Use InMemoryMessageBus (the default). In tests, resolve IMessageBus and publish directly:
var bus = serviceProvider.GetRequiredService<IMessageBus>();await bus.PublishAsync(new OrderCreated { OrderId = Guid.NewGuid() });The handler executes synchronously in the same thread.
Can I use multiple transports simultaneously?
Section titled “Can I use multiple transports simultaneously?”Yes. Use [OnBus("analytics")] on handlers and msg.AddBus("analytics", bus => bus.UseRabbitMq(...)) in config. Handlers without [OnBus] use the default bus.
How do I replay dead-lettered messages?
Section titled “How do I replay dead-lettered messages?”Inject IDeadLetterStore, call GetAllAsync(), deserialize, and re-publish:
var deadLetters = await deadLetterStore.GetAllAsync();foreach (var dl in deadLetters){ var message = JsonSerializer.Deserialize(dl.Payload, Type.GetType(dl.MessageType)!); await messageBus.PublishAsync(message!, dl.Context);}Is Pragmatic.Messaging AOT-compatible?
Section titled “Is Pragmatic.Messaging AOT-compatible?”The handler pipeline is 100% SG-generated (zero reflection). Serialization uses System.Text.Json which requires JsonSerializerContext for full AOT. The IMessageTypeRegistry switch expression is AOT-safe.
How do I monitor messaging health?
Section titled “How do I monitor messaging health?”Register health checks:
services.AddHealthChecks() .AddCheck<OutboxHealthCheck>("outbox") .AddCheck<ChannelTransportHealthCheck>("channels") .AddCheck<RabbitMqHealthCheck>("rabbitmq");Use the Pragmatic.Messaging ActivitySource and Meter for OpenTelemetry integration.
Can I use Pragmatic.Messaging without Pragmatic.Composition?
Section titled “Can I use Pragmatic.Messaging without Pragmatic.Composition?”Yes. Call services.AddPragmaticMessaging(msg => { ... }) directly and add services.AddPragmaticMessageHandlers() (SG-generated) for handler registration.
Getting Help
Section titled “Getting Help”- Showcase examples:
examples/showcase/src/Showcase.Billing/Events/Handlers/ - Design docs:
docs/architecture/messaging-p1-p3.md - GitHub Issues: github.com/anthropics/claude-code/issues