Steps to reproduce
Errors thrown by the APIRequestContext (page.request, request.newContext(), request fixture) lose all structured node error fields. Run:
// repro.mjs — npx playwright@latest repro.mjs (or via a test)
import { request } from '@playwright/test'
const context = await request.newContext()
try {
// Port 1 refuses connections: the underlying node error has `code: 'ECONNREFUSED'`.
await context.post('http://127.0.0.1:1/', { data: {} })
} catch (err) {
console.log('name :', err.name)
console.log('code :', err.code)
console.log('own props :', Object.getOwnPropertyNames(err))
console.log('message :', JSON.stringify(err.message.split('\n', 1)[0]))
}
await context.dispose()
Expected
The thrown error preserves the underlying node error's structured fields (at minimum err.code), so callers can distinguish network error kinds (ECONNRESET, ECONNREFUSED, EPIPE, …) programmatically. Plain node:http exposes err.code for exactly the same failure.
Actual
name : Error
code : undefined
own props : [ "stack", "message", "log", "name" ]
message : "apiRequestContext.post: connect ECONNREFUSED 127.0.0.1:1"
The error is rebuilt client-side from the driver payload, so only stack / message / log / name survive; the node code is dropped. The only remaining signal is the message first line (apiRequestContext.post: connect ECONNREFUSED host:port, … read ECONNRESET, … socket hang up), which callers have to parse as free text — a Request was cancelled for a URL containing "econnreset" anywhere in its call log would defeat such string matching.
Use case
Transient network errors (localhost flakiness under load) are commonly retried in test setup helpers. With err.code available this is a precise code === 'ECONNRESET' check; today it requires fragile message-text matching. #30978 added built-in maxRetries for ECONNRESET specifically, but any user-side retry / error classification logic still has no structured signal to work with.
Environment: Playwright 1.62.1, Windows x64, Node 26.
Steps to reproduce
Errors thrown by the
APIRequestContext(page.request,request.newContext(),requestfixture) lose all structured node error fields. Run:Expected
The thrown error preserves the underlying node error's structured fields (at minimum
err.code), so callers can distinguish network error kinds (ECONNRESET,ECONNREFUSED,EPIPE, …) programmatically. Plainnode:httpexposeserr.codefor exactly the same failure.Actual
The error is rebuilt client-side from the driver payload, so only
stack/message/log/namesurvive; the nodecodeis dropped. The only remaining signal is the message first line (apiRequestContext.post: connect ECONNREFUSED host:port,… read ECONNRESET,… socket hang up), which callers have to parse as free text — aRequest was cancelledfor a URL containing "econnreset" anywhere in its call log would defeat such string matching.Use case
Transient network errors (localhost flakiness under load) are commonly retried in test setup helpers. With
err.codeavailable this is a precisecode === 'ECONNRESET'check; today it requires fragile message-text matching. #30978 added built-inmaxRetriesforECONNRESETspecifically, but any user-side retry / error classification logic still has no structured signal to work with.Environment: Playwright 1.62.1, Windows x64, Node 26.