{"record":{"id":"fdfafbc5c5f8acb2","repo":"AvaloniaUI/Avalonia","slug":"this-already-has-an-owner","errorCode":null,"errorMessage":"{this} already has an owner.","messagePattern":"(.+?) already has an owner\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs","lineNumber":75,"sourceCode":"    public virtual void BuildString(StringBuilder builder, IReadOnlyList<ExpressionNode> nodes) \n    {\n        if (Index > 0)\n            nodes[Index - 1].BuildString(builder, nodes);\n        BuildString(builder);\n    }\n\n    /// <summary>\n    /// Sets the owner binding.\n    /// </summary>\n    /// <param name=\"owner\">The owner binding.</param>\n    /// <param name=\"index\">The index of the node in the binding path.</param>\n    /// <exception cref=\"InvalidOperationException\">\n    /// The node already has an owner.\n    /// </exception>\n    public void SetOwner(BindingExpression owner, int index)\n    {\n        if (Owner is not null)\n            throw new InvalidOperationException($\"{this} already has an owner.\");\n        Owner = owner;\n        Index = index;\n    }\n\n    /// <summary>\n    /// Sets the <see cref=\"Source\"/> from which the node will read its value and updates\n    /// the current <see cref=\"Value\"/>, notifying the <see cref=\"Owner\"/> if the value\n    /// changes.\n    /// </summary>\n    /// <param name=\"source\">\n    /// The new source from which the node will read its value. May be \n    /// <see cref=\"AvaloniaProperty.UnsetValue\"/> in which case the source will be considered\n    /// to be null.\n    /// </param>\n    /// <param name=\"dataValidationError\">\n    /// Any data validation error reported by the previous expression node.\n    /// </param>\n    public void SetSource(object? source, Exception? dataValidationError)","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs#L57-L93","documentation":"ExpressionNode.SetOwner throws InvalidOperationException when Owner is already non-null. Each ExpressionNode belongs to exactly one BindingExpression for its lifetime; reusing a node in a second binding would corrupt both expressions' node chains. The guard prevents silent double-ownership.","triggerScenarios":"Passing the same ExpressionNode instance into two different BindingExpression instances, or calling SetOwner twice on one node.","commonSituations":"Caching/sharing node instances to 'optimize' binding creation; a factory that returns pooled nodes without resetting ownership; a copy that aliases node references instead of cloning.","solutions":["Create fresh ExpressionNode instances for each binding; never reuse a node across BindingExpressions.","If pooling, ensure each node's Owner is cleared (or a new node created) before reuse.","When copying a node chain, deep-clone the nodes rather than aliasing them."],"exampleFix":"// before - reusing a node list across two expressions\nvar nodes = BuildNodes();\nexpr1.SetNodes(nodes);\nexpr2.SetNodes(nodes); // throws: already owned\n// after\nexpr1.SetNodes(BuildNodes());\nexpr2.SetNodes(BuildNodes());","handlingStrategy":"validation","validationCode":"// ExpressionNode instances must be uniquely owned. Never reuse across bindings.\nif (node.Owner is not null)\n    throw new InvalidOperationException(\"Node already owned; create a new instance.\");","typeGuard":"static bool IsUnowned(ExpressionNode n) => n.Owner is null;","tryCatchPattern":null,"preventionTips":["Never cache/share ExpressionNode instances across BindingExpressions.","Build a fresh node chain per binding.","When pooling, reset Owner (or recreate nodes) before reuse."],"tags":["data-binding","expression-node","ownership","internal-api"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}