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

  1. Pick the TTL the whole container must use and call HasAnalyticalStoreTimeToLive with that exact value on the document-root entity only.
  2. Remove all conflicting HasAnalyticalStoreTimeToLive calls from other types mapped to the same container.
  3. 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

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


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)