dotnet/efcore · error · InvalidOperationException
The time to live for analytical store was configured to
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 when the analytical-store time-to-live (AnalyticalStoreTimeToLive) differs across entity types mapped to the same Cosmos container. The Cosmos analytical store (Synapse Link) is a container-level property, so EF Core requires every type in a shared container to declare the same TTL. The validator captures the first non-null TTL and rejects any subsequent conflicting value.
Solutions
- Pick the TTL the whole container must use and call HasAnalyticalStoreTimeToLive with that exact value on the document-root entity only.
- Remove all conflicting HasAnalyticalStoreTimeToLive calls from other types mapped to the same container.
- If TTL should be null on some types, leave them unconfigured so the root value propagates.
Example fix
// before
modelBuilder.Entity<Order>().ToContainer("Orders").HasAnalyticalStoreTimeToLive(TimeSpan.FromHours(1));
modelBuilder.Entity<OrderHistory>().ToContainer("Orders").HasAnalyticalStoreTimeToLive(TimeSpan.FromDays(1));
// after
modelBuilder.Entity<Order>().ToContainer("Orders").HasAnalyticalStoreTimeToLive(TimeSpan.FromHours(1));
// OrderHistory inherits the container setting - do not call HasAnalyticalStoreTimeToLive again Defensive patterns
Strategy: validation
Validate before calling
var groups = dbContext.Model.GetEntityTypes()
.GroupBy(e => e.GetContainer());
foreach (var g in groups)
{
var ttls = g.Select(e => e.GetAnalyticalStoreTimeToLive()).Where(t => t != null).Distinct().ToList();
if (ttls.Count > 1) throw new InvalidOperationException($"Container {g.Key} has conflicting analytical TTLs");
} Prevention
- Set HasAnalyticalStoreTimeToLive on one root entity only per container.
- Use the same TimeSpan instance across configs to avoid silent value drift.
- Add a CI test that builds the model and asserts container-wide agreement.
When it happens
Trigger: One entity type calls HasAnalyticalStoreTimeToLive(TimeSpan) while another type sharing its container calls it with a different value, or only one of them configures it after an earlier type already set it. Fires during model validation on first DbContext use.
Common situations: Enabling Synapse Link partway through development on only the root entity while derived/shared types retain old TTL settings; refactoring entities to share a container without unifying TTL; values supplied in different units (seconds vs TimeSpan.FromHours) producing mismatched numbers.
Related errors
- The default time to live was configured to
- A full-text index is defined for
- A full-text index on
- A partition key is defined on entity type
- A vector index is defined for
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/e18d475462843eaf.
Report an issue: GitHub.
Appendix: 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 3a2006ef56)