{"record":{"id":"9abce4c9d6edb7f2","repo":"dotnet/efcore","slug":"unnamed-captured-variable","errorCode":null,"errorMessage":"Unnamed captured variable","messagePattern":"Unnamed captured variable","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs","lineNumber":2166,"sourceCode":"    protected override Expression VisitParameter(ParameterExpression parameter)\n    {\n        // Note that the parameter in the lambda declaration is handled separately in VisitLambda\n        if (_stack.Peek().Variables.TryGetValue(parameter, out var name)\n            || _liftedState.Variables.TryGetValue(parameter, out name))\n        {\n            Result = IdentifierName(name);\n\n            return parameter;\n        }\n\n        // This parameter is unknown to us - it's captured from outside the entire expression tree.\n        // Simply return its name without worrying about uniquification, since the variable needs to correspond to the outside in any\n        // case (it's the callers responsibility).\n        _capturedVariables.Add(parameter);\n\n        if (parameter.Name is null)\n        {\n            throw new NotSupportedException(\"Unnamed captured variable\");\n        }\n\n        Result = IdentifierName(parameter.Name);\n        return parameter;\n    }\n\n    /// <inheritdoc />\n    protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node)\n        => throw new NotSupportedException();\n\n    /// <inheritdoc />\n    protected override SwitchCase VisitSwitchCase(SwitchCase node)\n        => throw new NotSupportedException(\"Translation happens as part of VisitSwitch\");\n\n    /// <inheritdoc />\n    protected override Expression VisitSwitch(SwitchExpression switchNode)\n    {\n        Result = TranslateSwitch(switchNode, lowerableAssignmentVariable: null);","sourceCodeStart":2148,"sourceCodeEnd":2184,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs#L2148-L2184","documentation":"Thrown by the LINQ-to-C# expression-tree translator when it visits a ParameterExpression that is captured from outside the entire expression tree (not declared in any in-scope lambda) but whose Name property is null. Because the translator must emit the variable by its name into generated C#, an unnamed captured parameter cannot be represented. This lives in the precompiled-query / compiled-model translation pipeline that turns query expression trees back into source code.","triggerScenarios":"VisitParameter resolves a ParameterExpression that is absent from both the current scope's variable map and the lifted-state variable map (so it is treated as externally captured), and that ParameterExpression was constructed without a name argument (e.g. Expression.Parameter(typeof(int))).","commonSituations":"A query or value-generator expression is built programmatically with Expression.Parameter(type) omitting the name; a third-party extension hands EF an expression tree containing unnamed parameters; precompiled queries process a captured closure variable whose ParameterExpression lacks a name.","solutions":["Construct every ParameterExpression with an explicit name: Expression.Parameter(typeof(int), \"value\").","Audit manually-built expression trees for any ParameterExpression whose .Name is null before they reach EF precompilation.","If the unnamed parameter originates from a library, update or replace that library so it names its parameters."],"exampleFix":"// before\nvar p = Expression.Parameter(typeof(int));\n// after\nvar p = Expression.Parameter(typeof(int), \"value\");","handlingStrategy":"validation","validationCode":"// Walk the tree and fail fast on unnamed captured parameters before translation\nbool HasUnnamedParameters(Expression e)\n{\n    return new ParameterChecker().Visit(e).Any();\n}\n\nclass ParameterChecker : ExpressionVisitor\n{\n    readonly List<ParameterExpression> _bad = new();\n    protected override Expression VisitParameter(ParameterExpression p)\n    {\n        if (p.Name is null) _bad.Add(p);\n        return base.VisitParameter(p);\n    }\n}","typeGuard":"// Narrow to a safe-to-translate parameter\nstatic bool IsTranslatableParameter(ParameterExpression p) => !string.IsNullOrEmpty(p.Name);","tryCatchPattern":"// Wrap translation; surface a clear message\ntry { var csharp = translator.Translate(expr); }\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"Unnamed captured variable\"))\n{ throw new InvalidOperationException(\"Query contains an unnamed captured parameter; name all ParameterExpression instances.\", ex); }","preventionTips":["Always pass a name string to Expression.Parameter(type, name).","When accepting expression trees from callers, validate parameter names up front.","Unit-test expression builders against the translator to catch unnamed parameters early."],"tags":["expression-trees","precompiled-queries","compiled-model","linq"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}