dotnet/efcore · error · InvalidOperationException

The same ParameterExpression instance with name

Error message

The same ParameterExpression instance with name '{parameter}' was used as a variable declaration in a block and a nested block inside it. This is not allowed - use different ParameterExpression instances.

What it means

Thrown by LinqToCSharpSyntaxTranslator.VisitBlock when the same ParameterExpression instance is added as a variable to a non-lifted block scope (the local StackFrame) but it is already registered. LINQ treats ParameterExpression by reference identity; reusing one instance as a variable in both an outer and nested (non-lifted) block produces ambiguous C# because the variable's declaration scope is unclear.

Solutions

  1. Allocate a fresh ParameterExpression for each block scope that declares the variable; do not reuse instances across sibling/nested declaration scopes.
  2. If you must share by name, declare the variable once in the outermost block and do not re-declare it in nested blocks.
  3. Audit tree construction with Expression.Parameter equality-by-reference in mind — equal names do not imply equal identity.

Example fix

// before — same instance reused across nested block scopes
var v = Expression.Variable(typeof(int), "x");
var inner = Expression.Block(
    new[] { v },
    Expression.Assign(v, Expression.Constant(1)));
var outer = Expression.Block(
    new[] { v },
    inner,
    Expression.Add(v, Expression.Constant(2)));

// after — distinct instances per scope
var vOuter = Expression.Variable(typeof(int), "x");
var vInner = Expression.Variable(typeof(int), "x");
var inner = Expression.Block(
    new[] { vInner },
    Expression.Assign(vInner, Expression.Constant(1)));
var outer = Expression.Block(
    new[] { vOuter },
    inner,
    Expression.Add(vOuter, Expression.Constant(2)));
Defensive patterns

Strategy: validation

Validate before calling

// Verify no ParameterExpression is reused as a variable across nested blocks.
using System.Linq.Expressions;

bool HasSharedVariableInNestedBlocks(Expression e)
{
    var stack = new Stack<HashSet<ParameterExpression>>();
    bool clash = false;
    new NestedBlockVisitor(() => stack, () =>
    {
        // called when a duplicate is detected
        clash = true;
    }).Visit(e);
    return clash;
}

// A simplified visitor skeleton:
class NestedBlockVisitor : ExpressionVisitor
{
    private readonly Stack<HashSet<ParameterExpression>> _scope;
    private readonly Action _onClash;
    public NestedBlockVisitor(Func<Stack<HashSet<ParameterExpression>>> scope, Action onClash)
    { _scope = scope(); _onClash = onClash; }
    protected override Expression VisitBlock(BlockExpression b)
    {
        var current = new HashSet<ParameterExpression>();
        foreach (var v in b.Variables)
            if (!current.Add(v)) _onClash();
        _scope.Push(current);
        var r = base.VisitBlock(b);
        _scope.Pop();
        return r;
    }
}

Prevention

When it happens

Trigger: An expression tree built manually reuses a single ParameterExpression instance in the Variables collection of two nested BlockExpressions that are both rendered as statement scopes (i.e. neither is an expression-context block that gets lifted).

Common situations: Hand-rolled expression-tree builders that share a ParameterExpression across blocks for convenience; refactoring Expression.Variable calls into a shared field; converting imperative code that used the same symbol name into nested blocks.

Related errors


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

Appendix: source

Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:516

        {
            var (variables, variableNames) = (stackFrame.Variables, stackFrame.VariableNames);

            var uniquifiedName = UniquifyVariableName(parameter.Name ?? "unnamed");

            if (blockContext == ExpressionContext.Expression)
            {
                if (!_liftedState.Variables.TryAdd(parameter, uniquifiedName))
                {
                    throw new NotSupportedException("Parameter clash during expression lifting for: " + parameter.Name);
                }

                _liftedState.VariableNames.Add(uniquifiedName);
            }
            else
            {
                if (!variables.TryAdd(parameter, uniquifiedName))
                {
                    throw new InvalidOperationException(
                        DesignStrings.SameParameterExpressionDeclaredAsVariableInNestedBlocks(parameter.Name ?? "<null>"));
                }

                variableNames.Add(uniquifiedName);
            }
        }

        var unassignedVariables = block.Variables.ToList();

        var statements = new List<StatementSyntax>();
        LabeledStatementSyntax? pendingLabeledStatement = null;

        // Now visit the block's expressions
        for (var i = 0; i < block.Expressions.Count; i++)
        {
            var expression = block.Expressions[i];
            var onLastBlockLine = i == block.Expressions.Count - 1;
            _onLastLambdaLine = parentOnLastLambdaLine && onLastBlockLine;

View on GitHub (pinned to 3a2006ef56)