dotnet/efcore · error · InvalidOperationException

The stored procedure '{sproc}' cannot be configured to retur

Error message

The stored procedure '{sproc}' cannot be configured to return the rows affected because a rows affected parameter or a rows affected result column for this stored procedure already exists.

What it means

Thrown by StoredProcedure.SetIsRowsAffectedReturned when you try to mark a stored procedure as returning rows-affected via its return value, but a rows-affected OUTPUT parameter or a rows-affected result column already exists on that sproc. EF enforces one single mechanism for capturing rows affected per stored procedure.

Source

Thrown at src/EFCore.Relational/Metadata/Internal/StoredProcedure.cs:446

    public virtual bool IsRowsAffectedReturned
    {
        get => _isRowsAffectedReturned;
        set => SetIsRowsAffectedReturned(value);
    }

    /// <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 SetIsRowsAffectedReturned(bool rowsAffectedReturned)
    {
        EnsureMutable();

        if (_rowsAffectedParameter != null || _rowsAffectedResultColumn != null)
        {
            throw new InvalidOperationException(
                RelationalStrings.StoredProcedureRowsAffectedReturnConflictingParameter(
                    ((IReadOnlyStoredProcedure)this).GetStoreIdentifier()?.DisplayName()));
        }

        _isRowsAffectedReturned = rowsAffectedReturned;

        return rowsAffectedReturned;
    }

    private static void UpdateOverrides(
        StoreObjectIdentifier oldId,
        StoreObjectIdentifier? newId,
        IConventionEntityType entityType)
    {
        if (oldId == newId)
        {
            return;
        }

View on GitHub (pinned to dbf9771522)

Solutions

  1. Pick exactly one rows-affected mechanism: an output parameter, a result column, or the return value — and remove the others.
  2. If you already added a parameter/column, do not also call ReturnsRowsAffected().
  3. Reset the sproc mapping and reconfigure from scratch with a single approach.

Example fix

// before
var s = eb.InsertStoredProcedure();
s.AddRowsAffectedParameter();
s.ReturnsRowsAffected(); // throws - two mechanisms

// after
var s = eb.InsertStoredProcedure();
s.ReturnsRowsAffected();
Defensive patterns

Strategy: validation

Validate before calling

static void EnableRowsAffectedReturn(IConventionStoredProcedure sproc)
{
    if (sproc.FindRowsAffectedParameter() is not null
        || sproc.FindRowsAffectedResultColumn() is not null)
    {
        throw new InvalidOperationException(
            "Cannot enable return-value rows affected: a parameter or result column already exists.");
    }
    sproc.SetIsRowsAffectedReturned(true);
}

Prevention

When it happens

Trigger: StoredProcedure.cs:444-449: _rowsAffectedParameter != null || _rowsAffectedResultColumn != null when SetIsRowsAffectedReturned(true) is called. Reached via InsertStoredProcedure().AddRowsAffectedParameter()/AddRowsAffectedResultColumn() followed by .ReturnsRowsAffected() (or setting IsRowsAffectedReturned).

Common situations: Fluent config that mixes .AddRowsAffectedParameter() with .ReturnsRowsAffected(); scaffolding then manually re-configuring the sproc; copying sproc config and stacking two rows-affected mechanisms.

Related errors


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