Skip to content

Commit f5a7460

Browse files
kblokclaude
andcommitted
Fix Extensions.triggerAction: capture parent session before tab detaches
Tab targets are filtered out via SilentDetachAsync which removes them from Connection._sessions. When CdpPage is constructed shortly after, its call to client.ParentSession can no longer find the tab session by ID, causing TabId to fall back to the page target ID instead of the tab target ID. Chrome then rejects Extensions.triggerAction with "Action can only be triggered on a tab target." Fix: capture the parent session object reference at session-creation time (before SilentDetachAsync runs) so CdpPage always gets the correct tab target ID regardless of session lifecycle. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent f0f7dc2 commit f5a7460

2 files changed

Lines changed: 10 additions & 3 deletions

File tree

lib/PuppeteerSharp/Cdp/CdpCDPSession.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,24 @@ public class CdpCDPSession : CDPSession
4040
private readonly ConcurrentDictionary<int, MessageTask> _callbacks = new();
4141
private readonly string _parentSessionId;
4242
private readonly TargetType _targetType;
43+
private readonly CdpCDPSession _parentSessionRef;
4344
private int _lastId;
4445

45-
internal CdpCDPSession(Connection connection, TargetType targetType, string sessionId, string parentSessionId)
46+
internal CdpCDPSession(Connection connection, TargetType targetType, string sessionId, string parentSessionId, CdpCDPSession parentSessionRef = null)
4647
{
4748
Connection = connection;
4849
_targetType = targetType;
4950
Id = sessionId;
5051
_parentSessionId = parentSessionId;
52+
_parentSessionRef = parentSessionRef;
5153
}
5254

5355
/// <inheritdoc />
5456
public override bool Detached => Connection.IsClosed || IsClosed;
5557

5658
internal override CDPSession ParentSession
57-
=> string.IsNullOrEmpty(_parentSessionId) ? this : Connection.GetSession(_parentSessionId) ?? this;
59+
=> _parentSessionRef
60+
?? (string.IsNullOrEmpty(_parentSessionId) ? this : Connection.GetSession(_parentSessionId) ?? this);
5861

5962
internal bool IsClosed { get; private set; }
6063

lib/PuppeteerSharp/Cdp/Connection.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,11 @@ private void ProcessIncomingMessage(ConnectionResponse obj)
329329
{
330330
var param = obj.Params?.ToObject<ConnectionResponseParams>();
331331
var sessionId = param.SessionId;
332-
var session = new CdpCDPSession(this, param.TargetInfo.Type, sessionId, obj.SessionId);
332+
333+
// Capture the parent session reference now, before it may be removed from _sessions
334+
// by SilentDetachAsync (tab targets are filtered and detached quickly).
335+
var attachingParentSession = string.IsNullOrEmpty(obj.SessionId) ? null : GetSession(obj.SessionId);
336+
var session = new CdpCDPSession(this, param.TargetInfo.Type, sessionId, obj.SessionId, attachingParentSession);
333337
_sessions.AddItem(sessionId, session);
334338

335339
SessionAttached?.Invoke(this, new SessionEventArgs(session));

0 commit comments

Comments
 (0)