File-New-Project/EarTrumpet · warning · Exception
Device session parent is invalid but device is still notifyi
Error message
Device session parent is invalid but device is still notifying.
What it means
AudioDeviceSessionCollection.CreateAndAddSession is invoked from a COM session-notification callback (OnSessionCreated) and during enumeration. The parent IAudioDevice is held only via a WeakReference, so if the device object has been garbage-collected while the unmanaged IAudioSessionManager2 still holds the notification sink, _parent.TryGetTarget fails and the code throws to signal the inconsistency. Importantly the throw is inside a try block that catches all exceptions and logs them (line 82), so it does not propagate to the COM caller.
Source
Thrown at EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionCollection.cs:65
{
session.PropertyChanged -= Session_PropertyChanged;
}
foreach (var session in _movedSessions)
{
session.PropertyChanged -= MovedSession_PropertyChanged;
}
_sessionManager.UnregisterSessionNotification(this);
}
private void CreateAndAddSession(IAudioSessionControl session)
{
try
{
if (!_parent.TryGetTarget(out IAudioDevice parent))
{
throw new Exception("Device session parent is invalid but device is still notifying.");
}
var newSession = new AudioDeviceSession(parent, session, _dispatcher);
_dispatcher.BeginInvoke((Action)(() =>
{
if (newSession.State == SessionState.Moved)
{
_movedSessions.Add(newSession);
newSession.PropertyChanged += MovedSession_PropertyChanged;
}
else if (newSession.State != SessionState.Expired)
{
AddSession(newSession);
}
}));
}
catch (Exception ex)
{
View on GitHub (pinned to aa894e51c2)
Solutions
- Keep the existing try/catch in CreateAndAddSession (it already swallows and logs) — do not let this reach the COM boundary.
- Ensure the device's lifetime outlives UnregisterSessionNotification (unregister in Dispose, not only in the finalizer).
- If surfacing this in diagnostics, treat it as benign and lower its severity.
- Avoid constructing the collection for a device that is already being torn down.
Example fix
// the throw is already guarded; ensure unregister happens deterministically
// before: only finalizer unregisters
// after:
public void Dispose()
{
_sessionManager.UnregisterSessionNotification(this);
GC.SuppressFinalize(this);
} Defensive patterns
Strategy: try-catch
Validate before calling
// guard the weak parent before use
if (!_parent.TryGetTarget(out IAudioDevice parent))
{
Trace.WriteLine("Session parent collected; ignoring late notification.");
return;
} Try / catch
// CreateAndAddSession already wraps the throw in try/catch that logs; keep it.
try { /* create + add session */ } catch (Exception ex) { Trace.WriteLine($"CreateAndAddSession {ex}"); } Prevention
- Unregister COM session notifications in Dispose, not only the finalizer, to shorten the race window.
- Treat this exception as benign (logged) — never let it propagate to the COM callback boundary.
- Avoid keeping the device alive solely by the WeakReference; own its lifetime explicitly.
When it happens
Trigger: A new audio session notification arrives (OnSessionCreated) or an enumerated session is being added after the owning IAudioDevice was already collected — device removed/disposed while a late callback is in flight.
Common situations: Device disconnect/removal racing with GC and a pending session-created callback; finalizer ordering where the device dies before the collection unregisters its notification.
Related errors
AI-assisted analysis of File-New-Project/EarTrumpet@aa894e51c2 (2026-08-13).
Data as JSON: /api/errors/8c3cdd6ae1a80769.
Report an issue: GitHub.