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

  1. Read the specific errno in the log to identify cause: ECONNREFUSED = IP dead, EHOSTUNREACH = route blocked
  2. Update the candidate IP list (dns/providers / preSetIp config) with current working IPs for the domain
  3. Disable IPv6 candidates if the local network is IPv4-only
  4. 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

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


AI-assisted analysis of docmirror/dev-sidecar@7710cd56cc (2026-08-31). Data as JSON: /api/errors/8b110ccc45acf5c3. Report an issue: GitHub.