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

  1. Pick one TTL value and apply the same HasAnalyticalStoreTimeToLive(N) to every root entity type mapped to that container.
  2. Alternatively set TTL on a single root entity and remove the conflicting call from the other.
  3. 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

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


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/e18d475462843eaf. Report an issue: GitHub.