dotnet/wpf · error · ArgumentException
' ' is not a Visual or Visual3D.
Error message
'{0}' is not a Visual or Visual3D. What it means
VisualTreeUtils.EnsureVisual throws ArgumentException ('{0}' is not a Visual or Visual3D.) when the supplied DependencyObject is neither a Visual nor a Visual3D, and then calls VerifyAccess to enforce thread affinity. The library requires all elements it manipulates to derive from the visual layer, not merely from DispatcherObject/DependencyObject.
Solutions
- Cast to Visual or Visual3D first and reject anything that fails the cast
- Only pass elements that live in a visual tree (controls, panels, shapes)
- Ensure the call runs on the object's owning UI thread
Example fix
// before
VisualTreeUtils.EnsureNonNullVisual((DependencyObject)obj);
// after
if (obj is Visual || obj is Visual3D)
{
VisualTreeUtils.EnsureNonNullVisual((DependencyObject)obj);
} Defensive patterns
Strategy: type-guard
Validate before calling
bool isVisual = element is Visual || element is Visual3D;
Type guard
static bool IsVisualElement(DependencyObject d) => d is Visual || d is Visual3D;
Try / catch
try { VisualTreeUtils.EnsureNonNullVisual(element); }
catch (ArgumentException ex) when (ex.Message.Contains("not a Visual")) { /* handle non-visual element */ } Prevention
- Type fields/parameters as Visual or UIElement instead of DependencyObject when a visual is required
- Marshall calls to the UI thread (Dispatcher.Invoke) before visual-tree work
- Don't pass resources/freezables where visuals are expected
When it happens
Trigger: Passing a DependencyObject that is not a Visual — e.g. a freezable, a ResourceDictionary, a Binding expression, or a non-visual DependencyObject subclass — to an API guarded by EnsureNonNullVisual; also calling from a background thread (the subsequent VerifyAccess fails).
Common situations: Retrieving objects from Resources or code-behind fields typed as DependencyObject and assuming they are controls; passing Application-level or model objects; cross-thread access from a worker thread.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- 0x80070057
- Animation_AnimationTimelineTypeMismatch
- inverse ? SR.Visual_NotADescendant : SR.Visual_NotAnAncestor
- Page can have only Window or Frame as parent.
- Property data must be a non-reference variant compatible…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/f20ab7b003600529.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Media/VisualTreeUtils.cs:219
/// Throws if the given element is not a Visual or Visual3D
/// or if the Visual is on the wrong thread.
/// </summary>
private static void EnsureVisual(DependencyObject element, bool allowNull)
{
if (element == null)
{
if (!allowNull)
{
throw new ArgumentNullException(nameof(element));
}
return;
}
// Would DTypes be faster?
if (!(element is Visual || element is Visual3D))
{
throw new ArgumentException(SR.Visual_NotAVisual);
}
element.VerifyAccess();
}
/// <summary>
/// Throws if the given element is null or not a visual type, otherwise
/// either visual or visual3D will be non-null on exit.
/// </summary>
internal static void AsNonNullVisual(DependencyObject element, out Visual visual, out Visual3D visual3D)
{
ArgumentNullException.ThrowIfNull(element);
AsVisual(element, out visual, out visual3D);
Debug.Assert((visual == null) != (visual3D == null),
"Either visual or visual3D exclusively should be non-null.");
}View on GitHub (pinned to 81131a70a4)