{"record":{"id":"345fb1eb79eddb64","repo":"dotnet/efcore","slug":"visitchildren-must-be-overridden-in-the-class-de","errorCode":null,"errorMessage":"'VisitChildren' must be overridden in the class deriving from 'SqlExpression'.","messagePattern":"'VisitChildren' must be overridden in the class deriving from 'SqlExpression'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Cosmos/Query/Internal/Expressions/SqlExpression.cs","lineNumber":41,"sourceCode":"    /// </summary>\n    public override Type Type { get; } = type;\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public virtual CoreTypeMapping? TypeMapping { get; } = typeMapping;\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected override Expression VisitChildren(ExpressionVisitor visitor)\n        => throw new InvalidOperationException(CosmosStrings.VisitChildrenMustBeOverridden);\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public sealed override ExpressionType NodeType\n        => ExpressionType.Extension;\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected abstract void Print(ExpressionPrinter expressionPrinter);\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Cosmos/Query/Internal/Expressions/SqlExpression.cs#L23-L59","documentation":"The abstract SqlExpression.VisitChildren intentionally throws InvalidOperationException to force every concrete subclass to override VisitChildren (so expression-tree rewriting visits child SqlExpressions correctly). Hitting this means a SqlExpression subclass was visited without overriding the method.","triggerScenarios":"A custom SqlExpression subclass that did not override VisitChildren is passed through an ExpressionVisitor; or an internal expression type lost its override after a refactor.","commonSituations":"Writing a custom Cosmos query extension that introduces a new SqlExpression-derived type; provider regression after upgrades.","solutions":["Override VisitChildren in every custom SqlExpression subclass, returning a new instance when children change (and `this` when they don't).","Ensure internal expression types you depend on are from a consistent EF Core build (no mixed versions).","If you are an end user not subclassing SqlExpression, report it as a provider bug."],"exampleFix":"// before\nclass MyExpr : SqlExpression { /* no VisitChildren override -> throws on visit */ }\n\n// after\nprotected override Expression VisitChildren(ExpressionVisitor visitor)\n{\n    var child = (SqlExpression)visitor.Visit(Child);\n    return child == Child ? this : new MyExpr(child);\n}","handlingStrategy":"type-guard","validationCode":"// For custom SqlExpression subclasses, assert VisitChildren is overridden at startup.\nforeach (var t in Assembly.GetExecutingAssembly().GetTypes()\n            .Where(t => typeof(SqlExpression).IsAssignableFrom(t) && !t.IsAbstract))\n    if (t.GetMethod(nameof(Expression.VisitChildren),\n        BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,\n        Type.DefaultBinder, new[] { typeof(ExpressionVisitor) }, null)?.DeclaringType != t)\n        throw new InvalidOperationException($\"{t} must override VisitChildren.\");","typeGuard":"static bool OverridesVisitChildren(Type t)\n    => t.GetMethod(nameof(Expression.VisitChildren),\n        BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,\n        Type.DefaultBinder, new[] { typeof(ExpressionVisitor) }, null)?.DeclaringType == t;","tryCatchPattern":"try { visitor.Visit(mySqlExpression); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"VisitChildren\"))\n{ /* add VisitChildren override to the custom SqlExpression subclass */ }","preventionTips":["Always override VisitChildren in custom SqlExpression subclasses.","Add a reflection-based startup test verifying all SqlExpression subclasses override it."],"tags":["cosmos","internal","expression-tree","visitor"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}