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

  1. Keep the existing try/catch in CreateAndAddSession (it already swallows and logs) — do not let this reach the COM boundary.
  2. Ensure the device's lifetime outlives UnregisterSessionNotification (unregister in Dispose, not only in the finalizer).
  3. If surfacing this in diagnostics, treat it as benign and lower its severity.
  4. 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

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.