Skip to content

Diagnostics & Troubleshooting

Complete reference for all PRAG diagnostics emitted by the Pragmatic source generators and analyzers.


Pragmatic.Design uses Roslyn source generators and Roslyn analyzers to generate code at compile time. When the SG encounters invalid configurations, missing attributes, or suboptimal patterns, it emits diagnostics with IDs in the PRAG#### format.

These diagnostics appear:

  • In the Error List window in Visual Studio / Rider
  • In the build output of dotnet build
  • In CI logs
SeverityBuild EffectWhen Used
ErrorFails the buildInvalid attribute usage, missing requirements, incompatible code
WarningBuild succeeds with warningSuboptimal patterns, deprecated usage, performance concerns
InfoBuild succeeds silently (unless verbose)Suggestions, hints, informational messages
HiddenNot shown in outputRefactoring opportunities, code fix triggers

If you intentionally want to suppress a diagnostic, use any of these approaches:

<!-- In .csproj — suppress globally -->
<PropertyGroup>
<NoWarn>$(NoWarn);PRAG0303</NoWarn>
</PropertyGroup>
// In code — suppress locally
#pragma warning disable PRAG0303
public partial class MyDto { /* ... */ }
#pragma warning restore PRAG0303
# In .editorconfig — configure severity
[*.cs]
dotnet_diagnostic.PRAG0303.severity = none

Tip: Avoid suppressing Error-level diagnostics. They indicate real problems that will cause incorrect or missing generated code.


IDModuleSeverityTitleQuick Fix
PRAG0200ValidationErrorType must be partialAdd partial keyword
PRAG0201ValidationErrorValidator must implement IValidator<T>Implement the interface
PRAG0202ValidationWarningProperty has validation but type not partialAdd partial keyword
PRAG0203ValidationErrorComparison property not foundCheck nameof() reference
PRAG0204ValidationWarningValidateElements on non-collectionRemove attribute or change type
PRAG0205ValidationErrorValidateElements element type not validatableAdd validation attrs to element type
PRAG0206ValidationWarningValidator without validated typeAdd ISyncValidator to target
PRAG0209ValidationWarningIncompatible comparison typesUse compatible property types
PRAG0300MappingErrorType must be partialAdd partial keyword
PRAG0301MappingErrorSource type not foundCheck type reference exists
PRAG0302MappingErrorProperty not found on sourceCheck property name spelling
PRAG0303MappingWarningNo matching source propertyAdd [MapProperty] or [MapIgnore]
PRAG0304MappingErrorIncompatible typesAdd converter or change types
PRAG0305MappingErrorConverter must implement IValueConverterImplement correct interface
PRAG0306MappingErrorConverter needs parameterless constructorAdd public parameterless ctor
PRAG0307MappingWarningRequired property not mappedMap the property or remove required
PRAG0309MappingErrorNested type missing MapFromAdd [MapFrom<T>] to nested type
PRAG0310MappingErrorGenerateProjection requires MapFromAdd [MapFrom<T>] first
PRAG0311MappingWarningMethod cannot translate to SQLSimplify expression for EF Core
PRAG0312MappingErrorNested projection missing attributeAdd [GenerateProjection]
PRAG0313MappingInfoCircular reference detectedInformational — instance tracking used
PRAG0314MappingErrorConflicting MapIgnore and MapPropertyRemove one attribute
PRAG0315MappingErrorNested DTO property mismatchAlign DTO type with navigation
PRAG0316MappingErrorNo suitable constructorAdd constructor matching init-only props
PRAG0317MappingErrorNullable to non-nullable without DefaultAdd Default = ... to attribute
PRAG0319MappingWarningCustomizeMapping ignored in ProjectionUse non-projection mapping
PRAG0320MappingWarningMapConverter not supported in ProjectionRemove converter for projection
PRAG0321MappingInfoFormat not supported in ProjectionSimplify format for SQL
PRAG0322MappingInfoComplex dictionary not supportedUse [MapIgnore]
PRAG0323MappingWarningAmbiguous mappingAdd explicit [MapProperty]
PRAG0324MappingInfoID property excluded from ToEntityUse [MapProperty] to include
PRAG0325MappingHiddenSource property not mapped to DTOAdd property or [MapperIgnoreSource]
PRAG0400ActionsErrorAction class must be partialAdd partial keyword
PRAG0401ActionsErrorMust inherit DomainAction baseInherit DomainAction<T> or VoidDomainAction
PRAG0402ActionsInfoNo injectable dependenciesInformational — may be intentional
PRAG0404ActionsErrorLoadEntity ID property not foundAdd the ID property to the action
PRAG0405ActionsErrorLoadEntity key type not determinedEnsure entity has [Entity<TKey>]
PRAG0406ActionsErrorBoundary must be partialAdd partial to [Boundary] class
PRAG0407ActionsErrorBoundary must be in namespaceMove class into a namespace
PRAG0409ActionsErrorMutation must inherit Mutation<T>Inherit Mutation<TEntity>
PRAG0410ActionsErrorMutation mode not determinedAdd [Mutation(Mode = ...)] or use Create/Update prefix
PRAG0412ActionsWarningSubBoundary nesting too deepFlatten namespace structure
PRAG0413ActionsInfoSubBoundary inferred from namespaceInformational
PRAG0500EndpointsErrorEndpoint must be partialAdd partial keyword
PRAG0501EndpointsErrorMust inherit Endpoint baseInherit Endpoint<T> or VoidEndpoint
PRAG0502EndpointsErrorRoute is requiredAdd route to [Endpoint] attribute
PRAG0503EndpointsErrorToo many error typesReduce to 6 or fewer
PRAG0504EndpointsWarningRoute parameter not foundAdd matching public property
PRAG0505EndpointsErrorDuplicate endpoint nameUse unique endpoint names
PRAG0506EndpointsErrorInvalid rate limit configSpecify policy or Requests+Window
PRAG0507EndpointsErrorEndpoint group not foundCreate [EndpointGroup] class
PRAG0508EndpointsErrorProcessor must implement interfaceImplement pre/post processor interface
PRAG0510EndpointsInfoEndpoint registeredInformational
PRAG0511EndpointsInfoDomainAction endpoint detectedInformational
PRAG0512EndpointsInfoImplicit body bindingAdd [FromBody]/[FromQuery]/[FromRoute]
PRAG0515EndpointsErrorAutocomplete missing keyAdd Id or [Key] property to entity
PRAG0550EndpointsErrorAutocomplete requires stringApply to string properties only
PRAG0551EndpointsWarningVersioning requires Asp.Versioning.HttpAdd NuGet package reference
PRAG0600PersistenceErrorType must be partialAdd partial keyword
PRAG0601PersistenceErrorEntity type not foundCheck type reference exists
PRAG0602PersistenceErrorDatabase context must be partialAdd partial keyword
PRAG0603PersistenceErrorReadAccess cross-databaseUse same database or remove ReadAccess
PRAG0604PersistenceErrorReadAccess owner not includedAdd module reference
PRAG0610PersistenceErrorCollection without Relation attributeAdd [Relation.OneToMany<T>]
PRAG0611PersistenceErrorReference nav without RelationAdd [Relation.ManyToOne<T>]
PRAG0612PersistenceErrorAmbiguous relation needs WithNavigationAdd .WithNavigation("Name")
PRAG0613PersistenceErrorInverse property not foundCheck inverse name matches
PRAG0614PersistenceErrorInverse type mismatchFix relation pairing types
PRAG0615PersistenceErrorDuplicate navigation nameUse unique navigation names
PRAG0616PersistenceWarningPrefer OneToMany on parentMove relation to parent side
PRAG0617PersistenceInfoCross-boundary relation detectedInformational — FK only, no nav
PRAG0620PersistenceWarningState machine missing initial stateAdd [InitialState] to one value
PRAG0621PersistenceWarningUnreachable stateAdd [TransitionFrom] or [InitialState]
PRAG0622PersistenceErrorInvalid transition sourceUse valid enum member name
PRAG0650PersistenceWarningNavigation without foreign keyAdd FK property or configure manually
PRAG0651PersistenceWarningProperty may need value converterRegister a ValueConverter
PRAG0705QueryWarningRequired nav to soft-deletable entityMake navigation optional
PRAG0710QueryWarningDTO nav without IncludeCheck property name matches entity nav
PRAG0711QueryWarningDeep Include depth on loading profileReduce MaxDepth or use Projection
PRAG0716QueryWarningDTO with many navigation levelsUse Projection strategy
PRAG0800MessagingErrorHandler must implement IMessageHandler<T>Add interface implementation
PRAG0801MessagingWarningHandler should be partialAdd partial keyword
PRAG0802MessagingErrorInvalid retry configSet MaxAttempts > 0
PRAG0803MessagingErrorMiddleware must implement IMessageMiddlewareAdd interface implementation
PRAG0810MessagingErrorInconsistent saga transitionVerify state graph
PRAG0811MessagingInfoSaga state has no handlerAdd handler or confirm terminal
PRAG0812MessagingWarningSaga has unreachable statesAdd transitions to reach all states
PRAG0813MessagingErrorSaga state must be enumChange type parameter to enum
PRAG0814MessagingErrorSaga missing start handlerAdd [SagaStart] to one method
PRAG0815MessagingWarningCross-boundary without DependsOnAdd [DependsOn<TModule>]
PRAG0816MessagingWarningEvent without consumersAdd handler or remove event
PRAG0817MessagingErrorQueue name collisionRename one handler
PRAG0818MessagingWarningCross-boundary without outboxAdd [EnableOutbox] to DbContext
PRAG0830MessagingErrorEnableOutbox requires DbContextMove attribute to DbContext class
PRAG0831MessagingErrorEnableOutbox requires EFCore packageAdd Pragmatic.Messaging.EFCore ref
PRAG1000IdentityErrorIPermission.Name must be non-emptyReturn non-empty string from Name
PRAG1001IdentityErrorDuplicate permission nameUse unique permission names
PRAG1002IdentityWarningPermission name conventionUse boundary.sub.verb format
PRAG1003IdentityErrorIRole.Name must be non-emptyReturn non-empty string from Name
PRAG1050CompositionErrorDuplicate UsePackageRemove duplicate declaration
PRAG1100OwnershipErrorOwnedEntity requires partialAdd partial keyword
PRAG1102OwnershipErrorOwnedEntity requires Entity<T>Add [Entity<TKey>] attribute
PRAG1104OwnershipInfoOwnerId manually declaredInformational — SG skips generation
PRAG1600CompositionErrorModule requires unavailable middlewareAdd required middleware package
PRAG1601CompositionErrorModule dependency not declaredDeclare missing dependency
PRAG1602CompositionErrorCircular dependencyRemove circular module reference
PRAG1605CompositionWarningService without Composition refAdd Pragmatic.Composition reference
PRAG1606CompositionErrorDecorator requires CompositionAdd Pragmatic.Composition reference
PRAG1610CompositionErrorIncompatible schema versionUpdate packages to same major version
PRAG1611CompositionWarningNewer schema versionUpdate Pragmatic.Composition package
PRAG1612CompositionInfoLegacy schema versionInformational — compat mode
PRAG1620CompositionErrorInject references unregistered serviceRegister the service with [Service]
PRAG1621CompositionErrorInject creates circular referenceRefactor to break cycle
PRAG1630CompositionErrorStartupStep must implement IStartupStepImplement the interface
PRAG1631CompositionErrorStartupStep must be on a classMove attribute to class
PRAG1632CompositionErrorNeedsStep references unavailable typeAdd required package reference
PRAG1640CompositionErrorService requires classMove [Service] to a class
PRAG1641CompositionWarningDependency not registeredRegister or add [Service]
PRAG1642CompositionWarningLifetime mismatch (captive dependency)Align lifetimes
PRAG1643CompositionWarningNo interface foundUse AsSelf=true or add interface
PRAG1644CompositionInfoService registeredInformational
PRAG1645CompositionErrorAbstract class cannot be serviceRemove abstract or [Service]
PRAG1646CompositionWarningKeyed services require .NET 8+Upgrade to .NET 8+ or remove Key
PRAG1651CompositionWarningBoundary without databaseUse [Include<T, TDb>]
PRAG1652CompositionErrorDbContext name collisionUse distinct DbContext types
PRAG1660CompositionErrorDecorator must implement interfaceImplement at least one interface
PRAG1661CompositionErrorDecorator missing inner serviceAdd ctor parameter of decorated type
PRAG1670CompositionErrorEventHandler missing interfaceImplement IDomainEventHandler<T>
PRAG1680CompositionWarningExposeEndpoint not from packageUse [Endpoint] directly
PRAG1685CompositionErrorRemoteBoundary overlaps IncludeRemove one declaration
PRAG1686CompositionWarningRemoteBoundary has no actionsAdd actions or remove attribute
PRAG1687CompositionInfoRemoteBoundary base URL not configuredConfigure at runtime
PRAG1688CompositionWarningConfig key missing from appsettingsAdd key to appsettings.json
PRAG1690CompositionInfoDiscovered Pragmatic modulesInformational
PRAG1691CompositionInfoModule composition infoInformational
PRAG1693CompositionInfoNo services discoveredCheck [Service] usage
PRAG1694CompositionInfoNo startup steps discoveredInformational
PRAG1695CompositionWarningAuthorization without IdentityAdd Pragmatic.Identity reference
PRAG1696CompositionWarningIdentity.Persistence without AuthorizationAdd Pragmatic.Authorization reference
PRAG1700CachingErrorType must be partialAdd partial keyword
PRAG1701CachingErrorInvalid cache durationUse 5m, 1h, 1d format
PRAG1702CachingErrorNo cache key propertiesAdd at least one public property
PRAG1703CachingErrorInvalid placeholder in tag/keyCheck placeholder name matches property
PRAG1750CachingWarningDuplicate cache key orderAssign unique Order values
PRAG1751CachingWarningAll properties excludedKeep at least one property
PRAG1800I18nErrorInvalid translation fileFix JSON syntax
PRAG1801I18nWarningDuplicate translation keyConsolidate into single file
PRAG1802I18nWarningMissing translation keyAdd key to target culture
PRAG1803I18nInfoEmpty translation fileAdd key-value pairs
PRAG1900PatchErrorPatch type must be partialAdd partial keyword
PRAG1901PatchErrorEntity type not foundCheck type reference
PRAG1902PatchWarningNo patchable propertiesAdd settable properties
PRAG2000ConfigurationErrorConfiguration class must be partialAdd partial keyword
PRAG2001ConfigurationErrorCannot be static or abstractRemove modifier
PRAG2050ConfigurationWarningRequired property has defaultReconsider [Required] usage
PRAG2500JobsErrorMust implement IJob or IJob<T>Add interface
PRAG2501JobsErrorInvalid cron expressionProvide valid cron string
PRAG2502JobsWarningJob should be partialAdd partial keyword
PRAG2503JobsErrorDuplicate recurring job IDUse unique ID
PRAG2504JobsErrorInvalid retry MaxAttemptsSet MaxAttempts > 0
PRAG2505JobsErrorContinuation must be a jobImplement IJob on continuation type
PRAG2506JobsErrorContinuation cycle detectedRemove cyclic [ContinueWith]

Roslyn Analyzer Diagnostics (Pragmatic.Persistence.Analyzers)

Section titled “Roslyn Analyzer Diagnostics (Pragmatic.Persistence.Analyzers)”
IDModuleSeverityTitleQuick Fix
PRAG0680PersistenceWarningUse Entity.Create() instead of newReplace new Entity() with Entity.Create()
PRAG0681PersistenceWarningDo not use default for entitiesUse Entity.Create() factory
PRAG0682PersistenceWarningDo not use Activator.CreateInstanceUse Entity.Create() factory

PRAG0200 — Type with validation attributes must be partial

Section titled “PRAG0200 — Type with validation attributes must be partial”

What it means: You applied validation attributes (e.g., [Required], [MinLength]) to properties on a class that is not declared as partial.

Why it triggers: The SG needs to add a Validate() method to the class, which requires partial.

How to fix:

// Before
public class CreateUserRequest
{
[Required] public string Name { get; set; }
}
// After
public partial class CreateUserRequest
{
[Required] public string Name { get; set; }
}

PRAG0201 — Validator must implement IValidator<T>

Section titled “PRAG0201 — Validator must implement IValidator<T>”

What it means: A class marked with [Validator] does not implement IValidator<T>.

How to fix:

[Validator]
public class UserValidator : IValidator<CreateUserRequest>
{
public ValidationResult Validate(CreateUserRequest instance) { /* ... */ }
}

PRAG0203 — Comparison property not found

Section titled “PRAG0203 — Comparison property not found”

What it means: An attribute like [EqualTo("OtherProp")] or [GreaterThanProperty("OtherProp")] references a property that does not exist on the same type.

How to fix: Check spelling and ensure both properties are on the same type.

PRAG0205 — ValidateElements element type not validatable

Section titled “PRAG0205 — ValidateElements element type not validatable”

What it means: [ValidateElements] was used on a collection whose element type does not have validation attributes (i.e., does not implement ISyncValidator).

How to fix: Add validation attributes to the element type and make it partial.


What it means: A class with [MapFrom<T>] or [MapTo<T>] is not declared as partial.

How to fix: Add the partial keyword.

What it means: A target DTO property has no corresponding property on the source type (by name convention).

How to fix:

// Option A: map explicitly
[MapProperty(From = nameof(User.FullName))]
public string DisplayName { get; set; }
// Option B: ignore explicitly
[MapIgnore]
public string ComputedField { get; set; }

When to suppress: If you intentionally set the property manually after mapping.

What it means: The SG cannot auto-convert between source and target property types (e.g., int to string).

How to fix: Add a [MapConverter<TConverter>] attribute or change one of the types.

What it means: A target property is marked required but has no source mapping.

How to fix: Either map the property explicitly or remove the required modifier.

PRAG0310 — GenerateProjection requires MapFrom

Section titled “PRAG0310 — GenerateProjection requires MapFrom”

What it means: [GenerateProjection] was applied without a corresponding [MapFrom<T>]. Projection generation needs to know the source entity.

How to fix:

[MapFrom<User>]
[GenerateProjection]
public partial class UserDto { /* ... */ }

What it means: A property has both [MapIgnore] and [MapProperty] which contradict each other.

How to fix: Remove one of the two attributes.

PRAG0317 — Nullable to non-nullable without Default

Section titled “PRAG0317 — Nullable to non-nullable without Default”

What it means: A nullable source property maps to a non-nullable target without specifying a default.

How to fix:

[MapProperty(Default = "\"\"")] // default to empty string
public string Name { get; set; }

PRAG0325 — Source property not mapped to DTO

Section titled “PRAG0325 — Source property not mapped to DTO”

What it means: A source entity property is not represented in the target DTO. This is a Hidden diagnostic, useful for catching accidental omissions.

How to configure: Promote to Warning in .editorconfig:

dotnet_diagnostic.PRAG0325.severity = warning

What it means: A class using action attributes (e.g., [DomainAction], [Mutation]) must be partial so the SG can generate the invoker.

PRAG0401 — Must inherit from DomainAction base

Section titled “PRAG0401 — Must inherit from DomainAction base”

What it means: The action class does not inherit from DomainAction<T> or VoidDomainAction.

How to fix:

public partial class GetUser : DomainAction<UserDto>
{
public Guid UserId { get; set; }
// ...
}

PRAG0404 — LoadEntity ID property not found

Section titled “PRAG0404 — LoadEntity ID property not found”

What it means: [LoadEntity<TEntity>] specifies (or defaults to) an ID property name that does not exist on the action class.

How to fix: Add the ID property or specify the correct property name:

[LoadEntity<Reservation>(IdProperty = "ReservationId")]
public partial class UpdateReservation : Mutation<Reservation>
{
public Guid ReservationId { get; set; }
}

PRAG0409 — Mutation must inherit from Mutation<TEntity>

Section titled “PRAG0409 — Mutation must inherit from Mutation<TEntity>”

What it means: A class decorated with [Mutation] does not inherit from Mutation<TEntity>.

What it means: The SG cannot determine whether this is a Create or Update mutation.

How to fix:

// Option A: use a class name prefix
public partial class CreateReservation : Mutation<Reservation> { }
public partial class UpdateReservation : Mutation<Reservation> { }
// Option B: specify explicitly
[Mutation(Mode = MutationMode.Create)]
public partial class NewBooking : Mutation<Reservation> { }

PRAG0412 — SubBoundary nesting deeper than 2 levels

Section titled “PRAG0412 — SubBoundary nesting deeper than 2 levels”

What it means: The SG inferred a sub-boundary from namespace structure that is more than 2 levels deep. Deep nesting creates overly complex generated interfaces.

When to suppress: If the nesting is intentional and well-understood.


PRAG0500 — Endpoint class must be partial

Section titled “PRAG0500 — Endpoint class must be partial”

What it means: A class with [Endpoint] must be partial.

What it means: The [Endpoint] attribute must include a route pattern.

How to fix:

[Endpoint(HttpVerb.Get, "/api/users/{UserId}")]
public partial class GetUserEndpoint : Endpoint<UserDto> { }

What it means: A {parameter} in the route does not match any public property on the endpoint.

How to fix: Add a matching property:

[Endpoint(HttpVerb.Get, "/api/users/{UserId}")]
public partial class GetUserEndpoint : Endpoint<UserDto>
{
public Guid UserId { get; set; } // matches {UserId}
}

What it means: Two endpoints resolve to the same name, which breaks link generation.

How to fix: Rename one of the endpoint classes or specify a custom name in the attribute.

PRAG0515 / PRAG0550 — Autocomplete diagnostics

Section titled “PRAG0515 / PRAG0550 — Autocomplete diagnostics”

What they mean: [Autocomplete] requires the entity to have an identifiable key property, and the attribute must be placed on a string property.

How to fix:

[Entity<Guid>]
public partial class Amenity
{
[Autocomplete] // must be string
public string Name { get; set; }
}

PRAG0551 — Versioned methods require Asp.Versioning.Http

Section titled “PRAG0551 — Versioned methods require Asp.Versioning.Http”

What it means: Your endpoint has versioned methods (ExecuteV2, HandleAsyncV2, etc.) but the Asp.Versioning.Http NuGet package is not referenced. Without it, only the default version is generated.

How to fix: Add the NuGet package:

<PackageReference Include="Asp.Versioning.Http" Version="..." />

What it means: An entity or persistence-related type is not partial.

PRAG0603 / PRAG0604 — ReadAccess diagnostics

Section titled “PRAG0603 / PRAG0604 — ReadAccess diagnostics”

What they mean: [ReadAccess<T>] allows a boundary to read another boundary’s entity. PRAG0603 fires when the two boundaries use different databases (cross-DB join is impossible). PRAG0604 fires when the owner module is not referenced.

PRAG0610—PRAG0615 — Relation attribute diagnostics

Section titled “PRAG0610—PRAG0615 — Relation attribute diagnostics”

These diagnostics enforce proper use of [Relation.*] attributes.

PRAG0610 — Collection without Relation attribute:

// Before -- implicit collection triggers PRAG0610
[Entity<Guid>]
public partial class Order
{
public List<OrderItem> Items { get; set; } // PRAG0610
}
// After -- explicit relation
[Entity<Guid>]
[Relation.OneToMany<OrderItem>]
public partial class Order { }

PRAG0612 — Ambiguous relation:

// Two relations to the same target -- use WithNavigation to disambiguate
[Relation.OneToMany<Address>(WithNavigation = "HomeAddress")]
[Relation.OneToMany<Address>(WithNavigation = "WorkAddress")]
public partial class Person { }

PRAG0620—PRAG0622 — State Machine diagnostics

Section titled “PRAG0620—PRAG0622 — State Machine diagnostics”

PRAG0620 — Missing initial state:

public enum OrderStatus
{
[InitialState] // add this to fix PRAG0620
Draft,
[TransitionFrom(nameof(Draft))]
Confirmed,
[TransitionFrom(nameof(Confirmed))]
Completed
}

PRAG0622 — Invalid transition source: Ensure all [TransitionFrom] values match actual enum members.


PRAG0705 — Required navigation to soft-deletable entity

Section titled “PRAG0705 — Required navigation to soft-deletable entity”

What it means: A required navigation to a soft-deletable entity causes EF Core to INNER JOIN, which makes child rows disappear when the parent is soft-deleted.

How to fix: Make the navigation optional:

// Before
[Relation.ManyToOne<Organization>(Required = true)]
// After
[Relation.ManyToOne<Organization>(Required = false)]

What it means: A [LoadWith] profile with MaxDepth > 3 will generate complex SQL.

How to fix: Reduce depth or switch to Projection strategy:

[LoadWith<Order>(MaxDepth = 2)] // reduce depth
[LoadWith<Order>(Strategy = QueryStrategy.Projection)] // or use projection

3.7 Persistence Analyzers (PRAG0680—PRAG0682)

Section titled “3.7 Persistence Analyzers (PRAG0680—PRAG0682)”

These are Roslyn analyzers (not SG diagnostics) in Pragmatic.Persistence.Analyzers. They run on your application code to enforce the zero-reflection principle.

PRAG0680 — Use Entity.Create() instead of new

Section titled “PRAG0680 — Use Entity.Create() instead of new”

What it means: You wrote new Entity() instead of using the generated factory.

Why it matters: Entity.Create() ensures Guid v7 ID generation, audit timestamps, and default values.

How to fix:

// Before
var reservation = new Reservation();
// After
var reservation = Reservation.Create();

When to suppress: Never in application code. The analyzer already excludes generated code.

PRAG0681 — Do not use default for entities

Section titled “PRAG0681 — Do not use default for entities”

What it means: default(Entity) or default assigned to an entity variable bypasses initialization.

How to fix: Use Entity.Create() instead.

PRAG0682 — Do not use Activator.CreateInstance

Section titled “PRAG0682 — Do not use Activator.CreateInstance”

What it means: Activator.CreateInstance<Entity>() or Activator.CreateInstance(typeof(Entity)) creates an entity via reflection, bypassing the factory.

How to fix: Use Entity.Create(). Pragmatic follows a zero-reflection principle.


PRAG0800 — Handler must implement IMessageHandler<T>

Section titled “PRAG0800 — Handler must implement IMessageHandler<T>”

How to fix:

[MessageHandler]
public partial class InvoicePaidHandler : IMessageHandler<InvoicePaid>
{
public Task HandleAsync(InvoicePaid message, MessageContext ctx, CancellationToken ct)
{
// ...
}
}

How to fix:

[MessageHandler]
[Retry(MaxAttempts = 3, DelaySeconds = 5)] // MaxAttempts must be > 0
public partial class MyHandler : IMessageHandler<MyEvent> { }

These validate the state graph of [Saga<TState>] classes.

PRAG0814 — Saga has no start handler:

[Saga<BookingState>]
public partial class BookingSaga
{
[SagaStart] // required -- exactly one method
public Task HandleStart(BookingRequested msg) { /* ... */ }
[InState(BookingState.PaymentPending)]
public Task HandlePayment(PaymentReceived msg) { /* ... */ }
}

PRAG0812 — Unreachable states: Every non-initial state must be reachable via at least one transition from the start state. Check your [InState] and state assignment logic.

PRAG0830 / PRAG0831 — Outbox diagnostics

Section titled “PRAG0830 / PRAG0831 — Outbox diagnostics”

PRAG0830: [EnableOutbox] can only be applied to a class inheriting from DbContext.

PRAG0831: [EnableOutbox] requires a reference to Pragmatic.Messaging.EFCore:

<PackageReference Include="Pragmatic.Messaging.EFCore" />

3.9 Identity / Authorization (PRAG1000—PRAG1003)

Section titled “3.9 Identity / Authorization (PRAG1000—PRAG1003)”

PRAG1000 — IPermission.Name must be non-empty

Section titled “PRAG1000 — IPermission.Name must be non-empty”

How to fix:

public sealed class ViewReservations : IPermission
{
public static string Name => "booking.reservations.view"; // non-empty
}

What it means: Two IPermission implementations return the same Name string.

How to fix: Ensure each permission has a globally unique name.

What it means: The recommended format is boundary.sub-boundary.verb.

When to suppress: If your naming convention intentionally differs.


How to fix: Add partial to the class declaration.

PRAG1102 — OwnedEntity requires Entity<T>

Section titled “PRAG1102 — OwnedEntity requires Entity<T>”

What it means: [OwnedEntity] only works on classes that also have [Entity<TKey>].

How to fix:

[Entity<Guid>]
[OwnedEntity]
public partial class Reservation { /* ... */ }

3.11 Composition (PRAG1050, PRAG1600—PRAG1696)

Section titled “3.11 Composition (PRAG1050, PRAG1600—PRAG1696)”

What it means: Module A depends on Module B, which depends on Module A (directly or transitively).

How to fix: Refactor to break the cycle. Introduce a shared abstraction module if needed.

PRAG1605 — Service without Composition reference

Section titled “PRAG1605 — Service without Composition reference”

What it means: [Service] was used in a project that does not reference Pragmatic.Composition. The service will not be auto-discovered.

How to fix: Add a project/package reference to Pragmatic.Composition.

PRAG1642 — Lifetime mismatch (captive dependency)

Section titled “PRAG1642 — Lifetime mismatch (captive dependency)”

What it means: A Singleton service depends on a Scoped or Transient service, which causes the shorter-lived service to be “captured” and held alive longer than intended.

How to fix:

// Option A: make the dependent service Singleton too (if stateless)
[Service(Lifetime = ServiceLifetime.Singleton)]
public class MyCacheService : ICacheService { }
// Option B: inject IServiceScopeFactory and resolve per-request

What it means: Two different [Database] declarations generate DbContext classes with the same name.

How to fix: Use [Include<TModule, TDatabase, TDbContext>] with distinct DbContext type parameters.

PRAG1685 — RemoteBoundary overlaps Include

Section titled “PRAG1685 — RemoteBoundary overlaps Include”

What it means: A module is declared as both [Include<T>] (local) and [RemoteBoundary<T>] (remote). A boundary must be one or the other.

PRAG1695 / PRAG1696 — Module dependency chain warnings

Section titled “PRAG1695 / PRAG1696 — Module dependency chain warnings”

These warn about incomplete authorization/identity package chains. If you reference Pragmatic.Authorization, you typically also need Pragmatic.Identity, and vice versa for Identity.Persistence.


How to fix:

[Cacheable(Duration = "5m")] // 5 minutes
[Cacheable(Duration = "1h")] // 1 hour
[Cacheable(Duration = "1d")] // 1 day
[Cacheable(Duration = "00:30:00")] // TimeSpan format

What it means: A {PropertyName} placeholder in the cache key/tag template references a property that does not exist on the type.

How to fix: Verify the placeholder matches an existing public property name.


3.13 Internationalization (PRAG1800—PRAG1803)

Section titled “3.13 Internationalization (PRAG1800—PRAG1803)”

What it means: A *.json translation file has syntax errors.

How to fix: Validate the JSON file. Common issues: trailing commas, unquoted keys, BOM encoding.

What it means: A key exists in the default culture (e.g., en.json) but is missing in another culture (e.g., it.json). At runtime, the default culture value will be used as fallback.

How to fix: Add the missing key to the target culture file.


How to fix:

[GeneratePatch<Reservation>]
public partial class ReservationPatch { }

What it means: The target entity has no settable properties for patching.

When to suppress: If the entity intentionally uses only init-only or private-set properties.


PRAG2000 — Configuration class must be partial

Section titled “PRAG2000 — Configuration class must be partial”

How to fix: Add partial to the class with [Configuration].

PRAG2050 — Required property has default value

Section titled “PRAG2050 — Required property has default value”

What it means: A property marked [Required] also has a default value. The default satisfies the requirement, making [Required] effectively meaningless.

When to suppress: If you want to enforce explicit configuration even when a default exists.


PRAG2500 — Must implement IJob or IJob<T>

Section titled “PRAG2500 — Must implement IJob or IJob<T>”

How to fix:

[Job]
public partial class CleanupJob : IJob
{
public Task ExecuteAsync(CancellationToken ct) { /* ... */ }
}

How to fix:

[RecurringJob("0 2 * * *")] // daily at 2 AM -- valid cron
public partial class NightlyCleanup : IJob { }

What it means: Two [RecurringJob] classes resolve to the same ID (auto-generated from class name or explicitly set).

How to fix:

[RecurringJob("0 2 * * *", Id = "cleanup-orders")]
public partial class OrderCleanup : IJob { }
[RecurringJob("0 3 * * *", Id = "cleanup-logs")]
public partial class LogCleanup : IJob { }

PRAG2505 / PRAG2506 — Continuation diagnostics

Section titled “PRAG2505 / PRAG2506 — Continuation diagnostics”

PRAG2505: The type referenced by [ContinueWith<T>] must implement IJob or IJob<T>.

PRAG2506: A cycle in the continuation chain was detected (e.g., A continues with B, B continues with A). Remove one [ContinueWith] to break the cycle.


Use this decision tree when you expect generated code but nothing appears:

  1. Is the class partial? Almost every Pragmatic attribute requires the target class to be partial. Check for PRAG0200/0300/0400/0500/0600/1700/1900/2000/2500.

  2. Does the class inherit from the correct base?

    • Actions: DomainAction<T> or VoidDomainAction
    • Mutations: Mutation<TEntity>
    • Endpoints: Endpoint<T> or VoidEndpoint
  3. Are the NuGet references correct? Run dotnet build with verbosity set to diagnostic to see which SG pipelines are active:

    Terminal window
    dotnet build -v diag 2>&1 | grep "Pragmatic"
  4. Is FeatureDetector finding the module? Check for PRAG1690/1691 Info diagnostics. If no modules are discovered, ensure your library project references the correct Pragmatic runtime package.

  5. Clean and rebuild. SG output is cached aggressively. Force a clean rebuild:

    Terminal window
    dotnet clean && dotnet build
  6. Check for SG errors in build output. The SG may silently skip generation when it encounters an error. Look for PRAG entries in the Warning/Error list.

4.2 “I Get a PRAG Error but My Code Looks Correct”

Section titled “4.2 “I Get a PRAG Error but My Code Looks Correct””

Checklist:

  • Rebuild the solution. Stale SG state can report phantom errors.
  • Check namespace. Attributes must be from Pragmatic namespaces, not similarly named third-party ones.
  • Check using directives. Ensure you are importing the correct namespace for the attribute.
  • Check target framework. Some features require specific .NET versions (e.g., PRAG1646 for keyed services).
  • Check attribute spelling. Generic attributes ([Entity<Guid>]) vs non-generic ([Entity(typeof(Guid))]). Pragmatic exclusively uses generic attributes.
  • Verify package versions match. Mixed versions across Pragmatic packages can cause schema version diagnostics (PRAG1610/1611/1612).

For contributors adding diagnostics to the Pragmatic source generator:

  1. Determine the module and allocate an ID from the correct range (see shared/SourceGen/DiagnosticDescriptors.cs).
  2. Create or extend a *Diagnostics.cs file in the feature’s Diagnostics/ folder.
  3. Use DiagnosticFactory.Error/Warning/Info() from shared/SourceGen/:
    public static readonly DiagnosticDescriptor MyNewRule = DiagnosticFactory.Error(
    "PRAG0XXX",
    "Short title",
    "Message with '{0}' placeholder for context",
    "Longer description with fix guidance.");
  4. Report the diagnostic in the Transform or Feature using context.ReportDiagnostic(descriptor, location, args).
  5. Add a test in the module’s test project that verifies the diagnostic is emitted:
    [Fact]
    public void MyRule_InvalidInput_EmitsDiagnostic()
    {
    var source = "/* invalid code triggering the rule */";
    var result = RunGenerator(source);
    HasDiagnostic(result, "PRAG0XXX").Should().BeTrue();
    }
  6. Update this troubleshooting guide with the new diagnostic entry.

RangeModuleFile
PRAG0200—0299ValidationValidationDiagnostics.cs
PRAG0300—0399MappingMappingDiagnostics.cs
PRAG0400—0449ActionsActionsDiagnostics.cs
PRAG0500—0599EndpointsEndpointsDiagnostics.cs
PRAG0600—0699Persistence + EF CorePersistenceDiagnostics.cs
PRAG0680—0682Persistence AnalyzersDiagnosticDescriptors.cs (Analyzers)
PRAG0700—0716Query PipelineQueryPipelineDiagnostics.cs
PRAG0800—0831MessagingMessagingDiagnostics.cs
PRAG1000—1099Identity / AuthorizationIdentityDiagnostics.cs
PRAG1050—1059Package CompositionCompositionDiagnostics.cs
PRAG1100—1109Data OwnershipOwnershipDiagnostics.cs
PRAG1600—1699CompositionCompositionDiagnostics.cs
PRAG1700—1799CachingCachingDiagnostics.cs
PRAG1800—1899InternationalizationI18NDiagnostics.cs
PRAG1900—1999PatchPatchDiagnostics.cs
PRAG2000—2099ConfigurationConfigurationDiagnostics.cs
PRAG2500—2549JobsJobsDiagnostics.cs