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 its owner or some process metadata wasn’t readable • usually because the
process belongs to another user. kick list explains every - row in notes on stderr: a socket
that belongs to another user (named by account on Linux, such as root (uid 0)), a socket whose
owner wasn’t attributed, or a socket no readable process holds, which is normal for kernel-held
sockets. Re-run with higher privileges to fill in the owners. JSON keeps the row, with null
fields and "permission": "partial".
kill --port is refused before asking anything
On Linux, an unprivileged user can’t read other users’ processes, and any of them could share the
port’s socket. Kickoutchi can’t prove the visible owner is the only holder, so it refuses to signal
by port. The error names the verified owner and the command that works, for example
kick kill --pid 18422. Run that, or rerun with sudo.
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, and says why, for example that the socket belongs to
another user.
kill says the process is still running
The signal was delivered, but the process hadn’t exited two seconds later. Servers often close their
listener first and finish shutting down afterwards, so the port can be free while the process is
still alive. Wait and check again, or run the command the warning prints to send SIGKILL on Linux
and macOS. If the process closed its port, that command uses --tree, because a plain --pid kill
only targets port owners. The exit code is still 0, because the signal was accepted.
kill --pid says the PID “still exists but owns no visible open port”
A plain kick kill --pid only targets a process that owns a visible port, so a typo’d or unrelated
PID can’t be killed by accident. The process is alive but has no listener, often because it closed
it during shutdown. Run the suggested kick kill --pid PID --tree (add --force for SIGKILL); it
also stops the process’s children, so check them first with kick inspect --pid PID.
A batch kill sent nothing
When several targets are given, every one is resolved and authorized before any signal. If a single target can’t be resolved, is protected, or can’t be proven to own its port, the whole batch is refused and each refusal is listed. Fix or drop those targets and rerun. Kill protected processes on their own so they can be confirmed by PID or name.
A process “runs an executable that was deleted or replaced”
The binary file on disk changed after the process started. After a rebuild, this usually means an
old dev server is still running from the previous build. After a system upgrade, it means a daemon
is running the pre-upgrade binary. kick inspect --pid PID shows the original path and the process
family, and notes when init or a service manager adopted the process, a sign that its launcher
exited and left it orphaned.
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 3000defaults to127.0.0.1and::1. Your server may be binding0.0.0.0or a LAN address. Re-run with--all-addressesor an explicit--address. - Different protocol. The default is TCP. Add
--udpor--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 says owner_hidden
The endpoint is occupied, and a process probably holds it, but your account can’t see which one,
typically because it belongs to another user. On Linux the evidence names the UID that created the
socket. Rerun with sudo to identify the owner.
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. If you only care about definite matches, for example while following one PID, add
--matched-only to drop the indeterminate events.
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
LABELcolumn 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, andportall have to match, and TCP and UDP are separate. Useaddress = "*"for a protocol-and-port wildcard. - An exact selector always wins over a wildcard for the same endpoint.
- Hostnames, CIDR ranges, interface names, and
%zonesyntax are rejected • usescope_idfor 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.