[Bug]: WebKit emits pageerror for native RTCDataChannel send diagnostics without a JS exception
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 45/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- javascript, typescript
調査の方向性
Start by comparing WebKit's RTCDataChannel.cpp diagnostic path with Playwright's _onConsoleMessage in packages/playwright-core/src/server/webkit/wkPage.ts; the issue links both locations and a related report, #43120. Reproduce with the supplied finite script and check whether native failed-send diagnostics can be distinguished from unhandled JavaScript exceptions without hiding real exceptions. Done means the diagnostic remains observable but is no longer emitted as a pageerror.
索引モデルが issue の本文から書いたものです。
説明
Version and environment
Playwright 1.65.0, bundled WebKit revision 2388, Node v26.13.0, Linux x64, Ubuntu 24.04.5 LTS. The same diagnostic intermittently fails an actual three-peer WebRTC test on GitHub Actions.
Reproduction
Run the finite app-free script below with node rtc-handled-send.mjs after installing Playwright and its WebKit browser. It uses two local RTC peers, mock microphone permission/capture to permit host ICE candidates, no STUN server, no application accounts and two teardown sends. Readiness is bounded at ten seconds; all channels, capture tracks and the browser are closed.
// Three finite native sends: control, remote teardown, local teardown.
// Distinguish page JavaScript errors from WebKit's handled native diagnostic.
import assert from 'node:assert/strict';
import { webkit } from 'playwright';
const browser = await webkit.launch({ headless: true });
const diagnostics = [];
let phase = 'setup';
try {
const context = await browser.newContext({ permissions: ['microphone'] });
const page = await context.newPage();
page.on('console', (event) => { if (event.text().startsWith('native-probe:')) phase = event.text().slice(13); });
page.on('pageerror', (error) => diagnostics.push({ phase, name: error.name, message: error.message }));
await page.route('https://rtc-fixture.invalid/', (route) => route.fulfill({ contentType: 'text/html', body: '<title>Native RTC send</title>' }));
await page.goto('https://rtc-fixture.invalid/');
const result = await page.evaluate(async () => {
const errors = [];
globalThis.addEventListener('error', (event) => errors.push(event.message));
globalThis.addEventListener('unhandledrejection', (event) => errors.push(String(event.reason)));
const media = await navigator.mediaDevices.getUserMedia({ audio: true });
const a = new RTCPeerConnection({ iceServers: [] });
const b = new RTCPeerConnection({ iceServers: [] });
let timer;
let incoming;
try {
a.onicecandidate = (event) => { if (event.candidate) void b.addIceCandidate(event.candidate).catch(() => {}); };
b.onicecandidate = (event) => { if (event.candidate) void a.addIceCandidate(event.candidate).catch(() => {}); };
const channel = a.createDataChannel('bounded-native-fixture');
const ready = new Promise((resolve, reject) => {
timer = setTimeout(() => reject(new Error('native fixture readiness')), 10000);
b.ondatachannel = (event) => { incoming = event.channel; incoming.onmessage = () => resolve(); };
channel.onopen = () => channel.send('control');
});
ready.catch(() => {});
await a.setLocalDescription(await a.createOffer());
await b.setRemoteDescription(a.localDescription);
await b.setLocalDescription(await b.createAnswer());
await a.setRemoteDescription(b.localDescription);
await ready;
const sends = [];
const send = (phase) => {
const entry = { phase, state: channel.readyState, connection: a.connectionState };
try { channel.send('after teardown'); entry.sent = true; }
catch (error) { entry.caught = { name: error.name, message: error.message }; }
sends.push(entry);
};
console.log('native-probe:immediate-teardown');
b.close();
send('remote-close');
console.log('native-probe:local-close');
a.close();
send('local-close');
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
return { sends, errors };
} finally {
clearTimeout(timer);
incoming?.close(); a.close(); b.close();
media.getTracks().forEach((track) => track.stop());
}
});
// Flush native protocol diagnostics without a timed sleep.
await page.evaluate(() => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve))));
console.log(JSON.stringify({ result, diagnostics }, null, 2));
assert.deepEqual(result.errors, []);
} finally { await browser.close(); }
Observed
Both teardown channel.send() calls can return normally, while window.error and unhandledrejection remain empty. Playwright nevertheless emits pageerror with an empty error name and Error sending string through RTCDataChannel.. The last send can see channel.readyState === 'open' while its peer connection is already closed. This is a native asynchronous send diagnostic, not an escaped JavaScript exception. The current run emits the diagnostic for both teardown phases. A separate run waiting two animation frames between closes had no diagnostic and correctly caught InvalidStateError for the later closed channel.
WebKit's RTCDataChannel message queue logs a native transport failure using addConsoleMessage(MessageSource::JS, MessageLevel::Error, ...): https://github.com/WebKit/WebKit/blob/main/Source/WebCore/Modules/mediastream/RTCDataChannel.cpp#L72
Playwright's _onConsoleMessage promotes every JavaScript-source/error-level console message to a page error: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/webkit/wkPage.ts#L538
Expected and suggested approach
Keep the native failed-send diagnostic observable as a console/transport error, distinguishable from an unhandled JavaScript exception. Consider carrying an exception/native diagnostic discriminator in the WebKit protocol and using it in _onConsoleMessage, rather than promoting every JavaScript-source error. A message-text exclusion would risk concealing actual exceptions with matching text. I have not built or tested an upstream protocol patch.
Workaround and application limits
In our explicit departure test, wait for both surviving peers to process broker departure and dispose the departed connection before sending a new remaining-pair record. This avoids deliberately racing a stale peer and preserves the unchanged readiness deadline and pageerror checks. Do not ignore all RTC errors or infer remote delivery from send() returning; durable reconnect reconciliation/acknowledgements are still necessary.
Related prior WebKit native-console classification report: https://github.com/microsoft/playwright/issues/43120
Investigation and exact failed hosted run: https://github.com/link-foundation/meta-sovereign/pull/57 and https://github.com/link-foundation/meta-sovereign/actions/runs/43462136209/job/132013458396 .
- 主要言語
- TypeScript
- スター
- 99.7k
- フォーク
- 6.8k
- 平均マージ
- 16時間 10分
- マージ済み PR(30日)
- 301
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/playwright のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
microsoft/playwright#44109 ·
メンテナーはふだん 1 日以内に返信
-
[MCP]: --extension --background: noDefaults skips focus emulation, hidden tabs get no rAF and clicks time out対応中かも @microsoft-playwright-automation が今日担当しました。 オープンagent-triage
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
microsoft/playwright#44096 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
Crash tests fail with the Chromium sandbox on Linux対応中かも @microsoft-playwright-automation が今日担当しました。 オープンagent-triage needs-triage
難易度 4/5 3〜5日 初心者へのやさしさ 30/100
microsoft/playwright#44094 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
api review feedback Nov 11th, 2026対応中かも @luizpaulo-antunes が 1 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 70/100
microsoft/playwright#44062 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[Bug]: page.evaluate in Chromium never settles when its argument nests 60 objects deep対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープンagent-triage
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
microsoft/playwright#44060 · コメント 5 件 ·
メンテナーはふだん 1 日以内に返信
microsoft/playwright の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
pieterjanscheir/belgica#201 ·
メンテナーはふだん 1 日以内に返信
-
accessibility
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
numerique-gouv/lasuite-landingpage#311 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
oxc-project/tsgolint#1362 ·
メンテナーはふだん 1 日以内に返信
-
bug external xai
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
langchain-ai/langchain#41854 ·
メンテナーはふだん 1 日以内に返信
-
ready-for-agent
難易度 1/5 1〜3時間 初心者へのやさしさ 72/100
nemchik/biome-plugin-suitescript#137 ·
メンテナーはふだん 1 日以内に返信