docmirror/dev-sidecar · error

终止占用端口 ${port} 的进程失败。 PowerShell 方案: ${psError.message} CMD

Error message

终止占用端口 ${port} 的进程失败。
PowerShell 方案: ${psError.message}
CMD 方案: ${cmdError.message}

What it means

This is the aggregated failure of kill-by-port on Windows: both the PowerShell plan (Get-NetTCPConnection + Stop-Process) and the CMD plan (netstat -aon parsing + taskkill) failed. The thrown message embeds both underlying error messages (psError and cmdError), so it is the definitive diagnostic for 'could not free the port' on Windows.

Source

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

        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 状态的进程')
        }
        return true
      } catch (cmdError) {
        // 两种方案都失败,抛出包含原始错误信息的异常
        throw new Error(
          `终止占用端口 ${port} 的进程失败。\n`
          + `PowerShell 方案: ${psError.message}\n`
          + `CMD 方案: ${cmdError.message}`,
        )
      }
    }
  },

  async linux (exec, { port }) {
    // 主方案:lsof
    try {
      await exec(`kill $(lsof -i:${port} -t 2>/dev/null) 2>/dev/null || true`)
      return true
    } catch (_lsofError) {
      // 备选方案:fuser
      try {
        await exec(`fuser -k ${port}/tcp 2>/dev/null || true`)
        return true

View on GitHub (pinned to 7710cd56cc)

Solutions

  1. Read the 'PowerShell 方案:' and 'CMD 方案:' lines in the message to identify which stage failed.
  2. If 'access denied' appears, run DevSidecar (or the taskkill) from an elevated prompt: `taskkill /f /pid <pid> /t`.
  3. Manually identify the owner: `netstat -aon | findstr ":<port>"` then `tasklist /fi "PID eq <pid>"`, and close that application.
  4. If PowerShell execution policy blocks scripts, allow it: `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`.
  5. Reboot or use `Stop-Process -Id <pid> -Force` in an admin PowerShell as a last resort.
Defensive patterns

Strategy: fallback

Validate before calling

const { execSync } = require('child_process')
function findPortOwner(port) {
  try {
    const out = execSync(`powershell -NoProfile -Command "(Get-NetTCPConnection -LocalPort ${port} -State Listen).OwningProcess"`, { encoding: 'utf8' })
    return parseInt(out.trim(), 10) || null
  } catch { return null }
}

Type guard

function hasKillableOwner(port) {
  const pid = findPortOwner(port)
  return Number.isInteger(pid) && pid > 0
}

Try / catch

try {
  await killByPort({ port })
} catch (e) {
  const [psMsg = '', cmdMsg = ''] = e.message.split('\n').filter(l => l.includes('方案'))
  console.error(`kill-by-port failed. PS: ${psMsg} | CMD: ${cmdMsg}`)
  if (/denied|拒绝/i.test(e.message)) throw new Error('elevate privileges and retry')
  if (hasKillableOwner(port)) throw e // process still alive: escalate
  // else port already free — continue
}

Prevention

When it happens

Trigger: Calling the kill-by-port shell script on Windows when: (1) Get-NetTCPConnection is unavailable or the ps invocation itself fails, AND (2) the netstat fallback also fails (empty output / no LISTENING line / taskkill access denied / '未找到处于 LISTENING 状态的进程' from the inner fallback).

Common situations: Port held by a process running as another user or SYSTEM (taskkill denied); pwsh not on PATH on stripped-down Windows installs; antivirus blocking taskkill; port not actually listening at all; corporate policy blocking PowerShell script execution.

Related errors


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