dotnet/efcore · error · InvalidOperationException

The rows affected result column cannot be added to the…

Error message

The rows affected result column cannot be added to the stored procedure '{sproc}' because the rows affected are already returned via another column, via a parameter or via the stored procedure return value.

What it means

The rows-affected count may be returned through only one channel. AddRowsAffectedResultColumn() throws when rows affected is already carried by an existing result column, a parameter, or the stored procedure's return value. This mirrors AddRowsAffectedParameter() but guards the result-column channel.

Solutions

  1. Check FindRowsAffectedResultColumn(), FindRowsAffectedParameter(), and IsRowsAffectedReturned before adding a result column.
  2. Pick exactly one rows-affected channel and remove the others.
  3. If the procedure SELECTs rows affected, use .RowsAffectedResultColumn() alone.
  4. Rebuild the procedure mapping from scratch if the source of the duplicate channel is unclear.

Example fix

// before
sp.RowsAffectedParameter();
sp.RowsAffectedResultColumn(); // throws

// after
sp.RowsAffectedResultColumn();
Defensive patterns

Strategy: validation

Validate before calling

var sp = entityType.GetUpdateStoredProcedure();
if (sp is not null
    && sp.FindRowsAffectedResultColumn() is null
    && sp.FindRowsAffectedParameter() is null
    && !sp.IsRowsAffectedReturned)
{
    sp.RowsAffectedResultColumn();
}

Type guard

static bool CanAddRowsAffectedResultColumn(IStoredProcedure sp)
    => sp.FindRowsAffectedResultColumn() is null
       && sp.FindRowsAffectedParameter() is null
       && !sp.IsRowsAffectedReturned;

Prevention

When it happens

Trigger: Calling .RowsAffectedResultColumn() after .RowsAffectedParameter(), .RowsAffectedResultColumn(), or .RowsAffectedReturned() was already applied to the same stored procedure.

Common situations: Switching a procedure's rows-affected mechanism (e.g. from an output parameter to a SELECT result set) without removing the prior configuration; copy-pasting fluent blocks across Insert/Update/Delete mappings; conventions from a prior EF version leaving a residual channel after an upgrade.

Related errors


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

Appendix: source

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

    ///     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 StoredProcedureResultColumn? FindRowsAffectedResultColumn()
        => _rowsAffectedResultColumn;

    /// <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 StoredProcedureResultColumn AddRowsAffectedResultColumn()
    {
        if (_rowsAffectedResultColumn != null
            || _rowsAffectedParameter != null
            || _isRowsAffectedReturned)
        {
            throw new InvalidOperationException(
                RelationalStrings.StoredProcedureDuplicateRowsAffectedResultColumn(
                    ((IReadOnlyStoredProcedure)this).GetStoreIdentifier()?.DisplayName()));
        }

        var resultColumn = new StoredProcedureResultColumn(this, forRowsAffected: true, propertyName: null);
        _resultColumns.Add(resultColumn);
        _rowsAffectedResultColumn = resultColumn;

        return resultColumn;
    }

    /// <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 override string ToString()

View on GitHub (pinned to 3a2006ef56)