docmirror/dev-sidecar · info

没有找到占用该端口的进程

Error message

没有找到占用该端口的进程

What it means

When killing the process listening on a port on Windows, the primary PowerShell path may fail (e.g. Win7 without pwsh), and the fallback runs `netstat -aon | find ":port"` via cmd. If netstat returns nothing, there is no process bound to that port, so the fallback throws `没有找到占用该端口的进程` (no process found occupying this port).

Source

Thrown at packages/core/src/shell/scripts/kill-by-port.js:29

 * - mac:     lsof → fuser
 */
const executor = {
  async windows (exec, { port }) {
    // 主方案:PowerShell(更可靠,跨平台一致,Win7+ 默认可用)
    try {
      const cmds = [
        // 查找处于 Listen 状态的 TCP 连接并终止对应进程
        `$conn = Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | Where-Object { $_.State -eq 'Listen' } | Select-Object -First 1; if ($conn) { Stop-Process -Id $conn.OwningProcess -Force }`,
      ]
      await exec(cmds, { type: 'ps' })
      return true
    } catch (psError) {
      // 备选方案:CMD netstat + taskkill(Win7 无 pwsh 或 pwsh 执行失败时回退)
      // 分两步执行,避免 for /f 在 cmd /s /c 下的引号解析问题
      try {
        const output = await exec([`netstat -aon | find ":${port}"`], { type: 'cmd', printErrorLog: false })
        if (!output) {
          throw new Error('没有找到占用该端口的进程')
        }

        // 解析 netstat 输出,提取处于 LISTENING 状态的 PID
        const lines = output.split(/\r?\n/)
        let killed = false
        for (const line of lines) {
          if (!line.includes('LISTENING')) {
            continue
          }
          const parts = line.trim().split(/\s+/)
          const pid = parts[parts.length - 1]
          if (pid && /^\d+$/.test(pid)) {
            await exec([`taskkill /f /pid ${pid} /t`], { type: 'cmd', printErrorLog: false })
            killed = true
          }
        }
        if (!killed) {
          throw new Error('未找到处于 LISTENING 状态的进程')

View on GitHub (pinned to 7710cd56cc)

Solutions

  1. Check whether the port is actually in use first (`netstat -aon | find ":<port>"`) and skip the kill when nothing is listening.
  2. Verify the port number is the one dev-sidecar actually uses (default 31180/31181).
  3. Treat the error as a no-op success in restart scripts — the goal (port free) is already achieved.
  4. If the process exists but netstat misses it, run `Get-NetTCPConnection -LocalPort <port>` in PowerShell to get the PID and taskkill it manually.

Example fix

// before
await DevSidecar.shell.killByPort({ port: 31181 })
// after
const { execSync } = require('child_process')
let inUse = false
try {
  inUse = execSync(`netstat -aon | find ":31181"`).toString().length > 0
} catch (e) { /* find returns non-zero when no match */ }
if (inUse) {
  await DevSidecar.shell.killByPort({ port: 31181 })
}
Defensive patterns

Strategy: try-catch

Validate before calling

const { execSync } = require('child_process')
let inUse = false
try {
  execSync(`netstat -aon | find ":${port}"`)
  inUse = true
} catch (e) { /* no match => nothing listening */ }
if (!inUse) return // port already free, nothing to kill

Type guard

function isPortInUse (port) {
  try {
    require('child_process').execSync(`netstat -aon | find ":${port}"`)
    return true
  } catch (e) { return false }
}

Try / catch

try {
  await DevSidecar.shell.killByPort({ port })
} catch (err) {
  if (err.message === '没有找到占用该端口的进程') {
    log.info('port already free; nothing to kill')
  } else { throw err }
}

Prevention

When it happens

Trigger: Calling the kill-by-port shell API with a `port` that currently has no listener on Windows, or where netstat output is empty/filtered out (port already freed between check and kill; IPv6-only binding not matched by `find ":port"` with unusual formatting).

Common situations: Stopping dev-sidecar when the proxy already exited; restart scripts racing with process shutdown; typo'd port number; another tool already killed the listener.

Related errors


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