dotnet/efcore · error · InvalidOperationException

The stored procedure

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 when SetIsRowsAffectedReturned(true) is called on a stored procedure mapping that already has a rows-affected parameter or a rows-affected result column configured. EF exposes exactly one channel for rows-affected, so requesting the return variant on top of an existing one is ambiguous.

Solutions

  1. Remove the existing rows-affected parameter/result column before enabling IsRowsAffectedReturned.
  2. Choose a single rows-affected mechanism (parameter, result column, or return value) and configure only that one.
  3. Clear the stored procedure mapping and rebuild it with the desired rows-affected channel.

Example fix

// before
updateSproc.RowsAffectedParameter("rc");
updateSproc.IsRowsAffectedReturned = true; // throws

// after: pick one mechanism
updateSproc.IsRowsAffectedReturned = true;
// (do not also add a rows-affected parameter)
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling IsRowsAffectedReturned, ensure no parameter or result column exists.
if (sproc.RowsAffectedParameter is null && sproc.RowsAffectedResultColumn is null)
    sproc.IsRowsAffectedReturned = true;
else
    throw new InvalidOperationException(
        "Cannot enable rows-affected return: a rows-affected parameter or result column already exists.");

Prevention

When it happens

Trigger: StoredProcedure.SetIsRowsAffectedReturned(true) when _rowsAffectedParameter != null || _rowsAffectedResultColumn != null. Happens after calling RowsAffectedParameter(...), RowsAffectedResultColumn(...), and then trying to enable IsRowsAffectedReturned.

Common situations: Switching a stored procedure mapping from a rows-affected parameter to a return-value approach without first removing the parameter; building the mapping programmatically and adding multiple rows-affected channels; copy/paste of configuration calls.

Related errors


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

Appendix: 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 3a2006ef56)