{"record":{"id":"636f0333d2500319","repo":"elsa-workflows/elsa-core","slug":"ai-conversation-table-metadata-was-not-found","errorCode":null,"errorMessage":"AI conversation table metadata was not found.","messagePattern":"AI conversation table metadata was not found\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.AI.Persistence.EFCore/Services/EFCoreAIConversationCleanup.cs","lineNumber":49,"sourceCode":"            var sql = $@\"DELETE FROM {QuoteSqliteIdentifier(tableName)}\nWHERE \"\"RetentionMode\"\" = {{0}}\n  AND \"\"RetentionExpiresAt\"\" IS NOT NULL\n  AND \"\"RetentionExpiresAt\"\" <= {{1}}\";\n            return await dbContext.Database.ExecuteSqlRawAsync(\n                sql,\n                [configuredRetentionMode, now],\n                cancellationToken);\n        }\n\n        return await dbContext.Conversations\n            .Where(x => x.RetentionMode == configuredRetentionMode && x.RetentionExpiresAt != null && x.RetentionExpiresAt <= now)\n            .ExecuteDeleteAsync(cancellationToken);\n    }\n\n    private static string ResolveConversationTableName(AIDbContext dbContext)\n    {\n        var entityType = dbContext.Model.FindEntityType(typeof(AIConversationRecord)) ?? throw new InvalidOperationException(\"AI conversation entity metadata was not found.\");\n        return entityType.GetTableName() ?? throw new InvalidOperationException(\"AI conversation table metadata was not found.\");\n    }\n\n    private static bool IsSqliteProvider(string? providerName) =>\n        providerName?.Contains(\"Sqlite\", StringComparison.OrdinalIgnoreCase) == true;\n\n    private static string QuoteSqliteIdentifier(string identifier) => $\"\\\"{identifier.Replace(\"\\\"\", \"\\\"\\\"\", StringComparison.Ordinal)}\\\"\";\n}\n","sourceCodeStart":31,"sourceCodeEnd":57,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.AI.Persistence.EFCore/Services/EFCoreAIConversationCleanup.cs#L31-L57","documentation":"After finding the AIConversationRecord entity type, EFCoreAIConversationCleanup calls GetTableName(); a null result means the entity is mapped but has no table mapping (e.g. keyless or table-less configuration). Cleanup needs a concrete table name to build its SQL and throws InvalidOperationException otherwise.","triggerScenarios":"AIConversationRecord is configured without ToTable/table mapping (e.g. keyless entity, entity split or excluded from migrations) so GetTableName() returns null.","commonSituations":"Custom OnModelCreating overrides that call HasNoKey or ExcludeFromMigrations; partially applied mapping conventions after upgrades; test doubles using InMemory provider where table mapping differs.","solutions":["Add an explicit ToTable(\"AIConversations\") mapping for AIConversationRecord.","Remove HasNoKey/ExcludeFromMigrations configuration for the entity.","Use a real relational provider (SQLite/SqlServer) instead of InMemory for cleanup operations."],"exampleFix":"// before\nmodelBuilder.Entity<AIConversationRecord>().HasNoKey();\n// after\nmodelBuilder.Entity<AIConversationRecord>().ToTable(\"AIConversations\").HasKey(x => x.Id);","handlingStrategy":"validation","validationCode":"var entityType = dbContext.Model.FindEntityType(typeof(AIConversationRecord));\nvar table = entityType?.GetTableName();\nif (table is null) throw new InvalidOperationException(\"AIConversationRecord has no table mapping\");","typeGuard":"bool HasTableMapping(AIDbContext db) => db.Model.FindEntityType(typeof(AIConversationRecord))?.GetTableName() is not null;","tryCatchPattern":"try { await cleanup.RunAsync(ct); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"table metadata\")) { logger.LogError(ex, \"AIConversationRecord lacks a table mapping\"); }","preventionTips":["Always configure ToTable for AIConversationRecord.","Avoid HasNoKey/ExcludeFromMigrations on entities used by raw SQL cleanup.","Run cleanup only against relational providers."],"tags":["dotnet","ef-core","cleanup","model-metadata"],"backgroundTag":"entity-not-found","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}