dotnet/efcore · error · InvalidOperationException
The default time to live was configured to
Error message
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. What it means
Thrown when the default time-to-live (DefaultTimeToLive) differs across entity types mapped to the same Cosmos container. Default TTL is a container-level Cosmos setting that auto-expires documents, so every type sharing the container must agree. The validator keeps the first non-null value and throws on the next mismatch.
Solutions
- Choose the single TTL the container must use and apply it once on the document-root entity.
- Search for every HasDefaultTimeToLive call against entities mapped to the named container and delete the conflicting ones.
- Verify the units: HasDefaultTimeToLive expects a TimeSpan; double-check you did not pass seconds where hours were intended.
Example fix
// before
modelBuilder.Entity<User>().ToContainer("Users").HasDefaultTimeToLive(TimeSpan.FromDays(30));
modelBuilder.Entity<Guest>().ToContainer("Users").HasDefaultTimeToLive(TimeSpan.FromDays(7));
// after
modelBuilder.Entity<User>().ToContainer("Users").HasDefaultTimeToLive(TimeSpan.FromDays(30));
modelBuilder.Entity<Guest>().ToContainer("Users"); Defensive patterns
Strategy: validation
Validate before calling
foreach (var g in dbContext.Model.GetEntityTypes().GroupBy(e => e.GetContainer()))
{
var ttls = g.Select(e => e.GetDefaultTimeToLive()).Where(t => t != null).Distinct().ToList();
if (ttls.Count > 1) throw new InvalidOperationException($"Container {g.Key} has conflicting default TTLs");
} Prevention
- Configure HasDefaultTimeToLive once per container on the document root.
- Centralize TTL constants in one static class.
- Validate the built model in a unit test.
When it happens
Trigger: One entity type calls HasDefaultTimeToLive(TimeSpan) with one value and another type in the same container calls it with a different value (or with null while the first set a non-null value). Fires during model finalization/validation.
Common situations: Setting per-type TTLs before realizing the types share a container; migrating from per-entity TTL design to shared-container (TPT-like) design without scrubbing old TTL calls; mixing TimeSpan.Zero (no TTL) with non-zero values across the hierarchy.
Related errors
- The time to live for analytical store 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/c17cd3e9c4091f17.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:266
analyticalTtl,
conflictingEntityType.DisplayName(),
entityType.DisplayName(),
currentAnalyticalTtl,
container));
}
}
var currentDefaultTtl = entityType.GetDefaultTimeToLive();
if (currentDefaultTtl != null)
{
if (defaultTtl == null)
{
defaultTtl = currentDefaultTtl;
}
else if (defaultTtl != currentDefaultTtl)
{
var conflictingEntityType = mappedTypes.First(et => et.GetDefaultTimeToLive() != null);
throw new InvalidOperationException(
CosmosStrings.DefaultTTLMismatch(
defaultTtl,
conflictingEntityType.DisplayName(),
entityType.DisplayName(),
currentDefaultTtl,
container));
}
}
var currentThroughput = entityType.GetThroughput();
if (currentThroughput != null)
{
if (throughput == null)
{
throughput = currentThroughput;
}
else if ((throughput.AutoscaleMaxThroughput ?? throughput.Throughput)
!= (currentThroughput.AutoscaleMaxThroughput ?? currentThroughput.Throughput))View on GitHub (pinned to 3a2006ef56)