{"record":{"id":"d1adaa6c02a2843f","repo":"dotnet/wpf","slug":"sr-keyboardsinknotachild","errorCode":null,"errorMessage":"SR.KeyboardSinkNotAChild","messagePattern":"SR\\.KeyboardSinkNotAChild","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs","lineNumber":2238,"sourceCode":"            {\n                return _acquireHwndFocusInMenuMode;\n            }\n        }\n\n        /// <summary>\n        ///   The method is not part of the interface (IKeyboardInputSink).\n        /// </summary>\n        /// <param name=\"site\">The Site that containes the sink to unregister</param>\n        internal void CriticalUnregisterKeyboardInputSink(HwndSourceKeyboardInputSite site)\n        {\n            if(_isDisposed)\n                return;\n\n            if (null != _keyboardInputSinkChildren)\n            {\n                if (!_keyboardInputSinkChildren.Remove(site))\n                {\n                    throw new InvalidOperationException(SR.KeyboardSinkNotAChild);\n                }\n            }\n        }\n\n        private IKeyboardInputSink ChildSinkWithFocus\n        {\n            get\n            {\n                IKeyboardInputSink ikis=null;\n\n                if(null == _keyboardInputSinkChildren)\n                    return null;\n\n                foreach (HwndSourceKeyboardInputSite site in _keyboardInputSinkChildren)\n                {\n                    IKeyboardInputSite isite = (IKeyboardInputSite)site;\n\n                    if (isite.Sink.HasFocusWithin())","sourceCodeStart":2220,"sourceCodeEnd":2256,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs#L2220-L2256","documentation":"When an HwndSource child keyboard-input site is being detached, the code removes it from _keyboardInputSinkChildren; if the site is not in that list, Remove returns false and the code throws InvalidOperationException(SR.KeyboardSinkNotAChild). This means the caller tried to unregister a keyboard sink that this HwndSource never (or no longer) owns.","triggerScenarios":"Calling the child-site removal path with a HwndSourceKeyboardInputSite created by a different HwndSource, or a site that was already removed/disposed; double-disposal that unregisters the same site twice.","commonSituations":"Hosted interop control torn down twice (handle destroyed event plus explicit dispose); mismatched parent/child windows during reparenting; finalization racing with explicit cleanup.","solutions":["Unregister each child sink exactly once — guard removal with a flag so disposal paths don't run twice.","Only remove a site from the same HwndSource instance that registered it; verify parent identity before removal.","Check that the removal isn't triggered after the source was disposed, which may have already cleared the child list."],"exampleFix":"// before\nsite.Dispose();\nsite.Dispose(); // second call throws KeyboardSinkNotAChild\n// after\nprivate bool _siteRemoved;\npublic void RemoveSite(HwndSourceKeyboardInputSite site)\n{\n    if (_siteRemoved) return;\n    _siteRemoved = true;\n    site.Dispose();\n}\n","handlingStrategy":"validation","validationCode":"if (site == null || _removedSites.Contains(site)) return;\n_removedSites.Add(site);\nsite.Dispose();","typeGuard":null,"tryCatchPattern":"try\n{\n    site.Dispose();\n}\ncatch (InvalidOperationException)\n{\n    // site was not a child of this source (already removed or wrong parent)\n}","preventionTips":["Make dispose/idempotent: guard removal with a boolean flag.","Only remove sinks from the HwndSource that registered them.","Avoid double teardown (handle-destroyed event + explicit dispose both removing)."],"tags":["invalid-operation","keyboard","interop","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}