dotnet/efcore · error · InvalidOperationException

The rows affected parameter cannot be added to the stored pr

Error message

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

What it means

Thrown by StoredProcedure.AddRowsAffectedParameter when any rows-affected capture already exists — either a rows-affected parameter (_rowsAffectedParameter), a rows-affected result column, or the IsRowsAffectedReturned flag is set. EF permits exactly one rows-affected channel per stored procedure.

Source

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

    ///     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 StoredProcedureParameter? FindRowsAffectedParameter()
        => _rowsAffectedParameter;

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

        var parameter = new StoredProcedureParameter(this, rowsAffected: true, propertyName: null, originalValue: null);
        _parameters.Add(parameter);
        _rowsAffectedParameter = parameter;

        return parameter;
    }

    /// <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 IReadOnlyList<StoredProcedureResultColumn> ResultColumns

View on GitHub (pinned to dbf9771522)

Solutions

  1. Choose one rows-affected mechanism and remove the others before adding the parameter.
  2. Reset IsRowsAffectedReturned (reconfigure the sproc) if you intend to use a parameter instead of the return value.
  3. Audit the sproc builder calls so only one of parameter / result column / return value is used.

Example fix

// before
var s = eb.UpdateStoredProcedure();
s.ReturnsRowsAffected();
s.AddRowsAffectedParameter(); // throws

// after
var s = eb.UpdateStoredProcedure();
s.AddRowsAffectedParameter();
Defensive patterns

Strategy: validation

Validate before calling

static StoredProcedureParameter AddRowsAffectedParamOnce(StoredProcedure sproc)
{
    if (sproc.FindRowsAffectedParameter() is not null
        || sproc.FindRowsAffectedResultColumn() is not null
        || sproc.IsRowsAffectedReturned)
    {
        throw new InvalidOperationException("Rows affected already captured on this sproc.");
    }
    return sproc.AddRowsAffectedParameter();
}

Prevention

When it happens

Trigger: StoredProcedure.cs:573-580: _rowsAffectedParameter != null || _rowsAffectedResultColumn != null || _isRowsAffectedReturned. Produced by calling AddRowsAffectedParameter() after ReturnsRowsAffected() or AddRowsAffectedResultColumn().

Common situations: Stacking .ReturnsRowsAffected() and .RowsAffectedParameter(); scaffolding a sproc that returns rows affected and then adding a parameter manually; copying config blocks across insert/update sprocs.

Related errors


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