dotnet/efcore · error · InvalidOperationException
The time to live for analytical store was configured to '{tt
Error message
The time to live for analytical store 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 time to live for analytical store. What it means
Thrown by CosmosModelValidator.ValidateSharedContainerCompatibility when two document-root entity types mapped to the same Cosmos container declare different analytical-store time-to-live values via HasAnalyticalStoreTimeToLive(). Azure Cosmos DB applies analytical-store TTL at the container scope, so EF requires every type sharing a container to agree. The comparison uses entityType.GetAnalyticalStoreTimeToLive() (which already resolves to the root type's value for derived types).
Source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:246
{
throw new InvalidOperationException(
CosmosStrings.IsDiscriminatorMappingCompleteMismatch(
isDiscriminatorMappingComplete, firstEntityType.DisplayName(), entityType.DisplayName(),
currentIsDiscriminatorMappingComplete, container));
}
}
var currentAnalyticalTtl = entityType.GetAnalyticalStoreTimeToLive();
if (currentAnalyticalTtl != null)
{
if (analyticalTtl == null)
{
analyticalTtl = currentAnalyticalTtl;
}
else if (analyticalTtl != currentAnalyticalTtl)
{
var conflictingEntityType = mappedTypes.First(et => et.GetAnalyticalStoreTimeToLive() != null);
throw new InvalidOperationException(
CosmosStrings.AnalyticalTTLMismatch(
analyticalTtl,
conflictingEntityType.DisplayName(),
entityType.DisplayName(),
currentAnalyticalTtl,
container));
}
}
var currentDefaultTtl = entityType.GetDefaultTimeToLive();
if (currentDefaultTtl != null)
{
if (defaultTtl == null)
{
defaultTtl = currentDefaultTtl;
}
else if (defaultTtl != currentDefaultTtl)
{View on GitHub (pinned to dbf9771522)
Solutions
- Pick one TTL value and apply the same HasAnalyticalStoreTimeToLive(N) to every root entity type mapped to that container.
- Alternatively set TTL on a single root entity and remove the conflicting call from the other.
- Centralize container-level settings in a shared OnModelCreating helper/convention so they cannot drift.
Example fix
// before
modelBuilder.Entity<Order>().ToContainer("store").HasAnalyticalStoreTimeToLive(60);
modelBuilder.Entity<Customer>().ToContainer("store").HasAnalyticalStoreTimeToLive(120);
// after
modelBuilder.Entity<Order>().ToContainer("store").HasAnalyticalStoreTimeToLive(60);
modelBuilder.Entity<Customer>().ToContainer("store").HasAnalyticalStoreTimeToLive(60); Defensive patterns
Strategy: validation
Validate before calling
// In a unit test or Program.cs startup, force model validation early:
using (var ctx = new MyContext())
{
ctx.Model.GetModel(); // or ctx.GetService<IModelRuntimeInitializer>().Initialize(ctx.Model);
}
// Then assert container settings are uniform:
foreach (var grp in ctx.Model.GetEntityTypes()
.Where(e => e.FindPrimaryKey() != null && e.GetContainer() != null)
.GroupBy(e => e.GetContainer()))
{
var ttls = grp.Select(e => e.GetAnalyticalStoreTimeToLive()).Distinct().ToList();
Debug.Assert(ttls.Count <= 1, $"Container {grp.Key} has conflicting analytical TTLs");
} Try / catch
try { ctx.Database.EnsureCreated(); } // forces validation
catch (InvalidOperationException ex) when (ex.Message.Contains("time to live for analytical store"))
{
logger.LogError(ex, "Analytical TTL mismatch across entities in a shared container");
throw;
} Prevention
- Centralize all container-level Cosmos settings (TTL, throughput, partition key) in a single ApplyContainerDefaults(entity, container) helper.
- Write a model-validation unit test that builds the context and groups entities by container, asserting each container-level setting is uniform.
- Run dotnet ef migrations add / DbContext construction in CI to surface model errors before deploy.
When it happens
Trigger: Calling modelBuilder.Entity<A>().HasAnalyticalStoreTimeToLive(60) and modelBuilder.Entity<B>().HasAnalyticalStoreTimeToLive(120) where both A and B are mapped (via ToContainer or default) to the same container, during model validation (first DbContext use).
Common situations: Multi-entity shared-container designs where TTL was added to one entity during a feature spike but not propagated; merging configs from two teams each owning different entities in the same container; changing the TTL value in one place after copy-pasting config.
Related errors
- The default time to live was configured to '{ttl1}' on '{ent
- The provisioned throughput was configured to '{throughput1}'
- The provisioned throughput was configured as manual on '{man
- Cosmos automatic indexing is enabled for some entity types b
- The exception list configured for Cosmos automatic indexing
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/e18d475462843eaf.
Report an issue: GitHub.