{"record":{"id":"c17cd3e9c4091f17","repo":"dotnet/efcore","slug":"the-default-time-to-live-was-configured-to-ttl1","errorCode":null,"errorMessage":"The default time to live was configured to '{ttl1}' on '{entityType1}', but on '{entityType2}' it was configured to '{ttl2}'. All entity types mapped to the same container '{container}' must be configured with the same default time to live.","messagePattern":"The default time to live was configured to '(.+?)' on '(.+?)', but on '(.+?)' it was configured to '(.+?)'\\. All entity types mapped to the same container '(.+?)' must be configured with the same default time to live\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs","lineNumber":266,"sourceCode":"                            analyticalTtl,\n                            conflictingEntityType.DisplayName(),\n                            entityType.DisplayName(),\n                            currentAnalyticalTtl,\n                            container));\n                }\n            }\n\n            var currentDefaultTtl = entityType.GetDefaultTimeToLive();\n            if (currentDefaultTtl != null)\n            {\n                if (defaultTtl == null)\n                {\n                    defaultTtl = currentDefaultTtl;\n                }\n                else if (defaultTtl != currentDefaultTtl)\n                {\n                    var conflictingEntityType = mappedTypes.First(et => et.GetDefaultTimeToLive() != null);\n                    throw new InvalidOperationException(\n                        CosmosStrings.DefaultTTLMismatch(\n                            defaultTtl,\n                            conflictingEntityType.DisplayName(),\n                            entityType.DisplayName(),\n                            currentDefaultTtl,\n                            container));\n                }\n            }\n\n            var currentThroughput = entityType.GetThroughput();\n            if (currentThroughput != null)\n            {\n                if (throughput == null)\n                {\n                    throughput = currentThroughput;\n                }\n                else if ((throughput.AutoscaleMaxThroughput ?? throughput.Throughput)\n                         != (currentThroughput.AutoscaleMaxThroughput ?? currentThroughput.Throughput))","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs#L248-L284","documentation":"Thrown by CosmosModelValidator.ValidateSharedContainerCompatibility when two document-root entity types in the same container declare different default time-to-live values via HasDefaultTimeToLive(). Default TTL is a container-level Cosmos setting, so all entity types sharing a container must specify the same value. Derived types are compared through their root, so this fires only across distinct document roots.","triggerScenarios":"Calling HasDefaultTimeToLive(N) with different N on two entity types that resolve to the same container name, surfaced when the model is validated (e.g. first query, EnsureCreated, or dotnet ef database update).","commonSituations":"One entity configured for time-based document expiry and another in the same container left at a different/no TTL; refactoring an entity into a shared container without copying the TTL setting; environment-specific config where TTL differs by region.","solutions":["Align every root entity mapped to the container on the same HasDefaultTimeToLive(N) value.","If only one entity should 'own' the container setting, remove HasDefaultTimeToLive from the others.","Drive container-level options from a single configuration method applied to all shared-container roots."],"exampleFix":"// before\nmodelBuilder.Entity<Session>().ToContainer(\"state\").HasDefaultTimeToLive(300);\nmodelBuilder.Entity<Token>().ToContainer(\"state\").HasDefaultTimeToLive(900);\n\n// after\nconst int ContainerTtl = 300;\nmodelBuilder.Entity<Session>().ToContainer(\"state\").HasDefaultTimeToLive(ContainerTtl);\nmodelBuilder.Entity<Token>().ToContainer(\"state\").HasDefaultTimeToLive(ContainerTtl);","handlingStrategy":"validation","validationCode":"using (var ctx = new MyContext()) { ctx.Model.GetModel(); }\nforeach (var grp in ctx.Model.GetEntityTypes()\n    .Where(e => e.FindPrimaryKey() != null && e.GetContainer() != null)\n    .GroupBy(e => e.GetContainer()))\n{\n    var ttls = grp.Select(e => e.GetDefaultTimeToLive()).Distinct().ToList();\n    Debug.Assert(ttls.Count <= 1, $\"Container {grp.Key} has conflicting default TTLs\");\n}","typeGuard":null,"tryCatchPattern":"try { ctx.Model.GetModel(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"default time to live\"))\n{\n    logger.LogError(ex, \"Default TTL mismatch in shared Cosmos container\");\n    throw;\n}","preventionTips":["Keep TTL configuration in one place per container.","Add a test that asserts a single distinct GetDefaultTimeToLive per container group.","Document which entity 'owns' container-level settings for each container."],"tags":["cosmos","configuration","model-validation","ttl","shared-container"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}