docmirror/dev-sidecar · warning
[speed] test by TCP error:
Error message
[speed] test by TCP error:
What it means
testByTCP rejects and logs a warning when the raw TCP probe socket to a candidate IP emits an 'error' event. The probe measures connect latency to host:port using the given DNS; any socket error (refused, unreachable, reset) rejects the promise, marking that candidate unusable for IP selection.
Source
Thrown at packages/mitmproxy/src/lib/speed/SpeedTester.js:250
const startTime = Date.now()
let isOver = false
const timeout = 5000
let timeoutId = null
const client = net.createConnection({ host, port: this.port, family: host.includes(':') ? 6 : 4 }, () => {
isOver = true
clearTimeout(timeoutId)
const connectionTime = Date.now()
resolve({ status: 'success', by: 'TCP', target: `${host}:${this.port}`, time: connectionTime - startTime })
client.end()
})
client.on('error', (e) => {
isOver = true
clearTimeout(timeoutId)
log.warn('[speed] test by TCP error: ', this.hostname, `➜ ${host}:${this.port} from DNS '${dns}', cost: ${Date.now() - startTime} ms, errorMsg:`, e.message)
reject(e)
client.destroy()
})
timeoutId = setTimeout(() => {
if (!isOver) {
isOver = true
log.warn('[speed] test by TCP timeout:', this.hostname, `➜ ${host}:${this.port} from DNS '${dns}', cost: ${Date.now() - startTime} ms`)
reject(new Error('timeout'))
client.destroy()
}
}, timeout)
})
}
// 暂不使用
// testByPing (item) {
// return new Promise((resolve, reject) => {View on GitHub (pinned to 7710cd56cc)
Solutions
- Read the specific errno in the log to identify cause: ECONNREFUSED = IP dead, EHOSTUNREACH = route blocked
- Update the candidate IP list (dns/providers / preSetIp config) with current working IPs for the domain
- Disable IPv6 candidates if the local network is IPv4-only
- No action needed if at least one candidate passes — the tester selects the best available IP
Defensive patterns
Strategy: retry
Validate before calling
const net = require('net')
function tcpReachable(host, port, timeout = 3000) {
return new Promise(resolve => {
const s = net.connect(port, host)
s.setTimeout(timeout)
s.once('connect', () => { s.destroy(); resolve(true) })
s.once('error', () => resolve(false))
s.once('timeout', () => { s.destroy(); resolve(false) })
})
}
// pre-screen candidates before handing them to the tester Try / catch
try {
await tester.testByTCP(item)
} catch (e) {
if (['ECONNREFUSED','EHOSTUNREACH','ENETUNREACH'].includes(e.code)) {
dropCandidate(item.host)
}
} Prevention
- Pre-screen candidate IPs with a lightweight TCP check before speed testing
- Remove IPv6 candidates on IPv4-only networks
- Update IP source lists when a provider/CDN changes address ranges
- Accept single-candidate failures — selection only needs one reachable backup
When it happens
Trigger: Called from testOne for each backup IP: the TCP connect fails with ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ECONNRESET or similar before/instead of the timeout firing. The log includes cost in ms and the underlying error message.
Common situations: Testing candidate IPs where the service no longer listens (stale IP lists), blocked routes (common for github/docker IPs on some ISPs), or IPv6 addresses attempted on IPv4-only networks.
Related errors
- [speed] test by TCP timeout:
- [speed] test error: ${this.hostname} ➜ ${item.host}:${this
- 下载远程配置成功,但内容为空:
- 下载远程 domestic-domain-allowlist.txt 文件成功,但内容为空或内容太短,判断为无效的 do
- IPv6 地址 ${ip} 多次不可达(ENETUNREACH),已自动禁用 IPv6 DNS 解析
AI-assisted analysis of docmirror/dev-sidecar@7710cd56cc (2026-08-31).
Data as JSON: /api/errors/8b110ccc45acf5c3.
Report an issue: GitHub.