Elarion

Troubleshooting

Common symptoms when wiring Elarion, their likely cause, and the fix.

Most Elarion problems surface at build time as a missing generated method or an analyzer diagnostic rather than a runtime failure. This table maps the common symptoms to fixes.

Generation and registration

SymptomLikely causeFix
Add{Module}Handlers is missing[assembly: UseElarion] / [assembly: GenerateModuleHandlers] absent, or the generator is not referenced as an analyzer.Add the trigger attribute and the analyzer project/package reference.
Add{Module}Services is missingTrigger absent, no [Service] classes found in the module namespace, or the analyzer reference is missing.Add the trigger, annotate service classes with [Service], verify the analyzer reference.
A handler is not registeredThe class does not implement Elarion.Abstractions.IHandler<TRequest, TResponse>, or it is outside the module namespace.Check the interface namespace and module namespace containment.
A service is not registered[Service] class is outside the module namespace, the explicit contract is invalid, or no contract could be resolved.Move it under the module namespace; verify contract resolution.
Hosted service registration fails a diagnosticThe hosted service uses Scoped/Transient scope.Use Scope = ServiceScope.Singleton.
Generic service registration fails a diagnostic[Service] is on a generic type or one nested in a generic type.Register open generics manually for now.
Validation attributes are not enforced (ELVAL002)The request DTO carries DataAnnotations attributes but the compilation does not reference Elarion.Validation, or the host never calls AddElarionValidation().Reference Elarion.Validation from the application project and call services.AddElarionValidation() in the host.
Event consumer never runs (ELEVT003)The [ConsumeEvent] consumer's namespace is under no [AppModule], so it is not registered.Move the consumer under a module's namespace so that module wires it.
Handler-form consumer fails a diagnostic (ELEVT005)A class-level [ConsumeEvent] is not on an IHandler<TEvent, Result<T>> (or IHandler<TEvent>) whose request is an event, or the handler returns a non-Unit Result<T> (event consumers — domain or integration — are fan-out only).Implement the handler interface with an event request and return Result / Result<Unit>; for a typed reply use IHandlerSender/IHandler instead of the event bus.
RPC method is missingThe host lacks [GenerateModuleBootstrapper], the handler lacks [Handler], the handler's namespace is under no [AppModule], or the handler does not implement IHandler<TRequest, Result<TResponse>> (ELRPC002).Add the trigger, move the handler under a module, add the marker, and implement the handler interface with a Result<T> response.
Module services do not runThe module is disabled via Modules:{Name}:Enabled=false, or [AppModule] is missing.Check configuration and the module attribute.

JSON-RPC and schema generation

SymptomLikely causeFix
Build-time schema generation does not runElarionJsonRpcGenerateSchema is not true, the schema package is not referenced, or …GenerateSchemaOnBuild was disabled.Add the private package reference and set ElarionJsonRpcGenerateSchema=true, or invoke GenerateElarionJsonRpcSchema manually.
Schema generation fails after loading the appStartup code before builder.Build() threw, or no frozen JsonRpcDispatcher was registered before build.Register the dispatcher before builder.Build() and guard expensive startup work with JsonRpcSchemaGeneration.IsRunning.
Generated frontend RPC types are stalerpc-schema.json was updated but the client generator was not rerun.Export the schema and re-run the client generator.
Client generator fails on schema compositionThe schema uses unsupported constructs such as oneOf, anyOf, or allOf.Adjust the exported DTO shape, or extend the generator deliberately.

Persistence and serialization

SymptomLikely causeFix
Handler writes are not rolled back on failure; a warning says the in-memory (no-op) IUnitOfWork is in useNo durable unit of work is registered, so the transaction decorator falls back to the no-op default.Reference Elarion.EntityFrameworkCore.UnitOfWork and call services.AddElarionUnitOfWork<AppDbContext>() (EF-free hosts: AddElarionSqlUnitOfWork()).
System.Text.Json cannot serialize a DTO under AOTThe type is missing from a module JSON context.Add [JsonSerializable(typeof(…))] to the relevant module context.
DbSet<T> is missing for an entityThe entity has no [EntityConfiguration] (no IEntityTypeConfiguration<T> marked with [EntityConfiguration]), or its config's scope does not intersect the [GenerateDbSets("scope")] context.Add an [EntityConfiguration] for the entity with a matching scope.
A newly added same-assembly [EntityConfiguration] produces no DbSet<T> until the IDE is restartedNot a generator bug — dotnet build and the CLI always reflect current source. Rider/ReSharper's source-generator host refreshes generated code lazily and can lag when a new [EntityConfiguration] is added in the same assembly as the [GenerateDbSets] context. (A configuration in a referenced assembly never looks stale because it only becomes available after you build the producing project, and that build refreshes the host.)Build the project, or File → Invalidate Caches / Restart, to refresh the IDE host; the generated DbSet is correct once the host re-runs.
DbUpdateConcurrencyException when replacing a tracked parent's children (Children.Clear() + Add(new … { Id = … })) — but only on a real databaseEF's insert-vs-update heuristic misreads a set id on a key the model claims generated and issues an UPDATE for a row that was never inserted; the InMemory provider skips the affected-rows check, so tests stay green. On [GenerateDbSets] contexts the generated model already declares domain Guid PKs client-assigned, so this points at an entity outside the generated pass (foreign assembly, explicit ValueGeneratedOnAdd, or a hand-built context).Declare the key ValueGeneratedNever() for client-assigned ids (see Entity identity), and cover replace-children flows with a real-database (Testcontainers) test.
A PostgreSQL test suite's memory grows with every test; a heap dump shows thousands of NpgsqlDataSource instancesnew NpgsqlConnection(connectionString) registers a data source per distinct connection string in Npgsql's static pool manager for the life of the process (also with Pooling=false, and also through ClearPool(new NpgsqlConnection(cs))); with one database per test every test adds entries. Undisposed NpgsqlDataSource.Create(…) instances are retained by Npgsql's static metrics list.Open dedicated sessions with UnpooledNpgsqlSession.OpenAsync (Elarion.Sql.PostgreSql), dispose every data source you create, and clear pools with dataSource.Clear() on the data source the host uses. See One database per test.
Inserts fail with a Guid.Empty duplicate key after upgradingThe entity relied on EF's client-side Guid generator (Id never set in code); the generated model now declares domain Guid PKs ValueGeneratedNever (ADR-0038).Set ids at the creation site (Id = Guid.CreateVersion7(), recommended), or opt that entity back in with builder.Property(e => e.Id).ValueGeneratedOnAdd() — explicit configuration wins.

Still stuck? Open an issue at github.com/swimmesberger/Elarion/issues with a minimal repro.

On this page