Skip to content
Documentation menu

Troubleshooting

Diagnose missing sockets, withheld process metadata, permission errors, and scoped-kill refusals.

Start with the exact message or symptom below. Most cases come from socket state, operating-system permissions, or a safety check refusing an uncertain target.

A port shows in another tool but not in Kickoutchi

list and the TUI show listening TCP sockets and bound UDP sockets • the socket states that occupy a local port. Established and transitional connections are deliberately not in that view, so a port you see in a connection-oriented tool may not be a listener. Kickoutchi also uses native collectors rather than parsing ss, netstat, or lsof, so output can differ from those tools by design.

The full native state is collected • it just isn’t in the legacy view. kick list --snapshot-json and kick watch both retain every native TCP state, including established, time_wait, and the transitional ones.

Process metadata is missing (shows -)

The socket is visible but some process metadata wasn’t readable • usually because the process belongs to another user. The row still appears, tagged with partial permission so the blank is explained rather than hidden. Re-run with higher privileges to fill it in.

Permission denied when killing

You don’t have the rights to signal that process (exit 4). On Linux/macOS, try sudo; on Windows, use an elevated terminal. If a --port target has no readable owning PID, Kickoutchi reports permission denied rather than guessing.

A protected process asks for stronger confirmation

That’s protection working. Type the PID or the process name to confirm. If a process is protected that you’d rather treat normally, adjust your protected_processes • but the built-in safety names are there for good reasons.

kill --port says the target is ambiguous

Two or more PIDs own that port, so Kickoutchi refuses to guess. It prints the candidates; re-run with --pid and the one you mean.

why says the port is free, but my server still can’t bind

Three usual causes, and why distinguishes them if you read the per-endpoint rows:

  • Different address. why 3000 defaults to 127.0.0.1 and ::1. Your server may be binding 0.0.0.0 or a LAN address. Re-run with --all-addresses or an explicit --address.
  • Different protocol. The default is TCP. Add --udp or --all-protocols.
  • A race. A successful probe binds and immediately closes. It proves the endpoint was free at that instant; it does not reserve it. Something else can take it a millisecond later.

why exits 4 for a low port

Ports below 1024 usually need elevation to bind, so the probe is refused before it can learn anything. permission_denied is reported honestly rather than being turned into “free” or “busy” • current bindability is genuinely unknown. Re-run with elevation if you need a real answer.

watch printed collection_gap

A poll failed. Kickoutchi keeps the last valid snapshot rather than discarding it, so the failure can’t manufacture a wave of false release events, and it retries. If three consecutive polls fail, watch flushes the third gap and exits 1. Gaps ignore your endpoint filters on purpose • you always find out that you stopped seeing.

watch shows filter=indeterminate

Your filter needed a fact Kickoutchi couldn’t read • usually an owner PID or a process name behind a permission boundary. Rather than silently dropping the event, it’s emitted and marked indeterminate, so you know a filter might have hidden something. Definite non-matches are still suppressed.

watch missed a port that definitely opened

watch polls; it is not a kernel event feed. A socket that opens and closes between two polls is never observed, and several changes can collapse into one net difference. Lower --interval (down to 100ms) to narrow the window • you cannot close it.

My label isn’t showing up

  • The CLI and TUI only show a LABEL column when at least one label is configured. The TUI also needs a wide enough terminal. Structured output always carries the label.
  • Selectors are exact: protocol, address, and port all have to match, and TCP and UDP are separate. Use address = "*" for a protocol-and-port wildcard.
  • An exact selector always wins over a wildcard for the same endpoint.
  • Hostnames, CIDR ranges, interface names, and %zone syntax are rejected • use scope_id for an IPv6 scope.

See Endpoint labels for the validation rules.

Docker-owned port details are partial or unavailable

Docker context is enrichment, shown when the Docker CLI is available • it’s never required for normal port listing. Without the Docker CLI, you’ll still see the port and process, just not the container mapping.

Kickoutchi also disables PATH-resolved Docker enrichment while running as root, set-ID, with Linux capabilities, or from an elevated Windows token. This prevents a writable docker executable on PATH from crossing a privilege boundary. Run Kickoutchi without elevation when you specifically need optional container metadata; elevate only when OS process permissions require it.

Linux: kernel too old for pidfd termination

Listing ports works on older kernels, but safe pidfd-based termination needs Linux 5.3+. On a newer kernel, the signal is tied to a process handle so a recycled PID can’t be hit by mistake.

Windows: some processes need an elevated terminal

Higher-privilege processes can hide metadata or reject termination from a normal shell. Re-open your terminal as administrator and try again.

macOS: process identity changed before termination

macOS has no pidfd, so Kickoutchi re-checks the process identity right before signalling. If the PID was reused by a different process between your confirmation and the signal, it refuses and sends nothing. Re-list and try again.

Linux/macOS tree/group kill says it thawed everything

That means the scoped kill hit a safety refusal after freezing began: permission denied, identity drift, protected descendant, incomplete metadata, cap overflow, or a sweep that would not converge. Kickoutchi sent SIGCONT to every member it had stopped and sent no termination signal.

If a cleanup error names PIDs, those are processes whose SIGCONT was refused and which may still be stopped • check them. A member that exited during the freeze is not reported, because there is nothing left to resume.

Windows tree kill reports incomplete metadata or partial containment

Windows tree kill has no SIGSTOP equivalent. It preflights before the Job Object commit and fails closed if missing creation-time metadata could hide a descendant. After commit it freezes the job for a final validation sweep, and if a live member can’t join the job it withholds termination entirely rather than terminating that one process individually • doing so would reopen the descendant-spawn window it just closed. Delivered, already-exited, unconfirmed, and not-terminated PIDs are all reported separately instead of collapsing into “success”.

Windows: --group or TUI t/T is unavailable

That’s expected. Windows supports read-only inspect and CLI --tree, but --group is a POSIX process-group feature and the Windows TUI still omits the tree keys. If inspect or CLI --tree is unknown on Windows, run kick --version and update to the latest release.

The TUI says “Terminal too small”

The table needs at least 80×20. Resize the window (or zoom out your terminal font) and the UI comes back.

kickoutchi-update is missing

The updater shipped with the installer starting at a certain release. If you installed earlier, rerun the latest installer once to opt in • future upgrades can then use kickoutchi-update.