dotnet/efcore · error · InvalidOperationException

The entity type ' ' was configured to use ' ', but the…

Error message

The entity type '{entityType}' was configured to use '{sproc}', but the store name was not specified. Configure the stored procedure name explicitly.

What it means

Thrown inside the local ValidateStoredProcedureName function when StoreObjectIdentifier.Create(entityType, storedProcedureType) returns null — meaning the stored procedure's store name cannot be derived (RelationalModelValidator.cs:516-522). This happens when the sproc is configured but no name/schema was supplied and no convention could fill it.

Solutions

  1. Supply the stored-procedure name explicitly: .InsertUsingStoredProcedure("dbo.CustomerInsert", sp => { ... }) (and likewise for Update/Delete).
  2. If using the overload that takes a builder without a name, add .HasName("YourSproc") inside the configuration.
  3. Ensure conventions that compute default names are enabled (haven't been removed via modelBuilder.Model.RemoveConvention(...)).
  4. Verify the entity itself has a name (entityType.DisplayName()) so the convention has something to base the sproc name on.

Example fix

// before — name omitted, convention yields nothing
modelBuilder.Entity<Customer>()
    .InsertUsingStoredProcedure(sp =>
    {
        sp.HasParameter(c => c.Id);
        sp.HasResultColumn(c => c.Id);
    });

// after — explicit store name and schema
modelBuilder.Entity<Customer>()
    .InsertUsingStoredProcedure("dbo.CustomerInsert", sp =>
    {
        sp.HasParameter(c => c.Id);
        sp.HasResultColumn(c => c.Id);
    });
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    foreach (StoreObjectType kind in new[] { StoreObjectType.InsertStoredProcedure, StoreObjectType.UpdateStoredProcedure, StoreObjectType.DeleteStoredProcedure })
    {
        if (StoreObjectIdentifier.Create(et, kind) is null
            && (kind == StoreObjectType.InsertStoredProcedure ? et.GetInsertStoredProcedure()
              : kind == StoreObjectType.UpdateStoredProcedure ? et.GetUpdateStoredProcedure()
              : et.GetDeleteStoredProcedure()) is not null)
        {
            throw new InvalidOperationException($"Entity '{et.Name}' has a {kind} with no store name; call .HasName(...).");
        }
    }
}

Try / catch

try { _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("store name was not specified"))
{
    logger.LogError("Supply an explicit sproc name. {Msg}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: Calling .InsertUsingStoredProcedure(sp => { }) with an empty/null name or relying on convention-based name resolution when conventions are disabled or the entity name is unset. Also when a custom IModelCustomizer strips the name annotation.

Common situations: Using the lambda overload that omits the explicit name and the default-name convention produced an empty string; setting HasName(null); scaffolding generated incomplete sproc config; running with model caching where the name was conditionally set and the cache key didn't differentiate.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/16eae5e3c083182f. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:519

            sprocCount++;
        }

        if (sprocCount > 0
            // TODO: Support this with #28703
            //&& sprocCount < 3
            && entityType.GetTableName() == null)
        {
            throw new InvalidOperationException(RelationalStrings.StoredProcedureUnmapped(entityType.DisplayName()));
        }

        static void ValidateStoredProcedureName(
            StoreObjectType storedProcedureType,
            IEntityType entityType)
        {
            var sprocId = StoreObjectIdentifier.Create(entityType, storedProcedureType);
            if (sprocId == null)
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureNoName(
                        entityType.DisplayName(), storedProcedureType));
            }
        }
    }

    /// <summary>
    ///     Validates a single stored procedure and all entity types mapped to it.
    /// </summary>
    /// <param name="mappedTypes">The entity types mapped to the stored procedure.</param>
    /// <param name="storedProcedure">The stored procedure identifier.</param>
    /// <param name="logger">The logger to use.</param>
    protected virtual void ValidateStoredProcedure(
        IReadOnlyList<IEntityType> mappedTypes,
        in StoreObjectIdentifier storedProcedure,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
        => ValidateStoredProcedureCompatibility(mappedTypes, storedProcedure, logger);

View on GitHub (pinned to 3a2006ef56)