[Bug]: WebKit emits pageerror for native RTCDataChannel send diagnostics without a JS exception
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 45/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- javascript, typescript
- Lĩnh vực
- backend-api-design, testing-qa
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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 .
- Ngôn ngữ chính
- TypeScript
- Star
- 99.7k
- Fork
- 6.8k
- Merge trung bình
- 16 giờ 10 phút
- Pull request đã merge (30 ngày)
- 301
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của microsoft/playwright
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
microsoft/playwright#44109 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[MCP]: --extension --background: noDefaults skips focus emulation, hidden tabs get no rAF and clicks time outCó thể đã có người làm @microsoft-playwright-automation đã nhận hôm nay. Đang mởagent-triage
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 25/100
microsoft/playwright#44096 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Crash tests fail with the Chromium sandbox on LinuxCó thể đã có người làm @microsoft-playwright-automation đã nhận hôm nay. Đang mởagent-triage needs-triage
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 30/100
microsoft/playwright#44094 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
api review feedback Nov 11th, 2026Có thể đã có người làm @luizpaulo-antunes đã nhận 1 ngày trước. Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 70/100
microsoft/playwright#44062 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: page.evaluate in Chromium never settles when its argument nests 60 objects deepCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mởagent-triage
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 25/100
microsoft/playwright#44060 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của microsoft/playwright
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
pieterjanscheir/belgica#201 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
No skip link to the main contentĐang mởaccessibility
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
numerique-gouv/lasuite-landingpage#311 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
oxc-project/tsgolint#1362 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug external xai
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
langchain-ai/langchain#41854 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
ready-for-agent
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 72/100
nemchik/biome-plugin-suitescript#137 ·
Maintainer thường phản hồi trong vòng 1 ngày