dotnet/efcore · error · InvalidOperationException

The object ' ' has been removed from the model.

Error message

The object '{name}' has been removed from the model.

What it means

Accessing the Builder of a StoredProcedureParameter that was removed from the model throws, because its internal _builder field has been nulled. This indicates the parameter is no longer part of the live metadata graph.

Solutions

  1. Stop caching parameter metadata objects across model mutations; re-query from the current model.
  2. Guard access with the IsInModel property before touching .Builder.
  3. Re-fetch the parameter via StoredProcedure.FindParameter(name) on the current procedure.
  4. Review convention ordering so code does not run after the parameter has been removed.

Example fix

// before
var oldParam = proc.Parameters[0];
proc.RemoveParameter(oldParam.Name);
var b = oldParam.Builder; // throws

// after
var param = proc.FindParameter(name);
if (param is { IsInModel: true })
{
    var b = param.Builder;
}
Defensive patterns

Strategy: validation

Validate before calling

if (parameter.IsInModel)
{
    var builder = parameter.Builder;
}

Type guard

static bool IsLiveParameter(StoredProcedureParameter p)
    => p.IsInModel;

Prevention

When it happens

Trigger: Holding a stale StoredProcedureParameter reference after the procedure (or the parameter) was removed via model configuration, then reading .Builder or invoking a builder API on it.

Common situations: Convention code that caches parameter references across a model rebuild; calling RemoveParameter / reconfiguring the procedure while another code path still references the old parameter object; snapshotting metadata and using it after the model was finalized.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Metadata/Internal/StoredProcedureParameter.cs:61

        if (rowsAffected)
        {
            _direction = ParameterDirection.Output;
            _directionConfigurationSource = ConfigurationSource.Explicit;
        }

        _builder = new InternalStoredProcedureParameterBuilder(this, storedProcedure.Builder.ModelBuilder);
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public virtual InternalStoredProcedureParameterBuilder Builder
    {
        [DebuggerStepThrough]
        get => _builder ?? throw new InvalidOperationException(CoreStrings.ObjectRemovedFromModel(Name));
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public virtual bool IsInModel
        => _builder is not null
            && StoredProcedure.IsInModel;

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>

View on GitHub (pinned to 3a2006ef56)