derailed/k9s · error
kubectl command must not be in the current working directory
Error message
kubectl command must not be in the current working directory: %w
What it means
runK() resolves kubectl with exec.LookPath. Since Go 1.19, LookPath returns the sentinel error exec.ErrDot when the resolved binary is a relative path — i.e. kubectl was found in the current working directory (./kubectl), which Go refuses to use implicitly for security (a hostile writable directory could hijack command resolution). k9s surfaces this explicitly instead of silently running the local binary.
Source
Thrown at internal/view/exec.go:61
var editorEnvVars = []string{"K9S_EDITOR", "KUBE_EDITOR", "EDITOR"}
type shellOpts struct {
clear, background bool
pipes []string
binary string
banner string
args []string
}
func (s shellOpts) String() string {
return fmt.Sprintf("%s %s", s.binary, strings.Join(s.args, " "))
}
func runK(a *App, opts *shellOpts) error {
bin, err := exec.LookPath("kubectl")
if errors.Is(err, exec.ErrDot) {
return fmt.Errorf("kubectl command must not be in the current working directory: %w", err)
}
if err != nil {
return fmt.Errorf("kubectl command is not in your path: %w", err)
}
args := []string{opts.args[0]}
if u, err := a.Conn().Config().ImpersonateUser(); err == nil {
args = append(args, "--as", u)
}
if g, err := a.Conn().Config().ImpersonateGroups(); err == nil {
args = append(args, "--as-group", g)
}
if isInsecure := a.Conn().Config().Flags().Insecure; isInsecure != nil && *isInsecure {
args = append(args, "--insecure-skip-tls-verify")
}
args = append(args, "--context", a.Config.K9s.ActiveContextName())
if cfg := a.Conn().Config().Flags().KubeConfig; cfg != nil && *cfg != "" {
args = append(args, "--kubeconfig", *cfg)
}View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Install kubectl into a real PATH directory (e.g. /usr/local/bin/kubectl) so it resolves absolutely
- Remove or rename the ./kubectl in your working directory before launching k9s
- Launch k9s from a directory that does not contain a kubectl binary
Example fix
# before — running k9s from a dir containing ./kubectl $ cd ~/project && ls kubectl $ k9s # any kubectl-backed feature fails with ErrDot # after $ sudo mv ~/project/kubectl /usr/local/bin/kubectl $ k9s # resolves via PATH, works
Defensive patterns
Strategy: validation
Validate before calling
// preflight: resolve kubectl and refuse cwd-relative hits before running
bin, err := exec.LookPath("kubectl")
if errors.Is(err, exec.ErrDot) {
return fmt.Errorf("refusing ./kubectl — install kubectl on PATH")
}
if path.IsAbs(bin) { /* safe to proceed */ } Prevention
- Never keep a kubectl binary in directories you launch k9s from
- Install kubectl under /usr/local/bin or ~/.local/bin listed early in PATH
- Treat exec.ErrDot as a security signal — a writable-dir binary hijack, not an inconvenience
When it happens
Trigger: Starting k9s in a directory that contains a kubectl executable and no earlier PATH entry wins — e.g. you downloaded kubectl into a project folder and launch k9s from there, invoking any kubectl-shelling feature (shell, port-forward helpers, kubectl prompts).
Common situations: Per-project kubectl binaries (version managers that drop kubectl into ./bin with PATH=.:/bin styles); CI scripts that cd into a tools directory; users following install docs that say 'download kubectl here' and run k9s in the same dir.
Related errors
- kubectl command is not in your path: %w
- expected Unstructured, but got %T
- shell exec failed: %w
- command failed. Check k9s logs: %w
- node is cordoned
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/4af179fbd7d2ca9d.
Report an issue: GitHub.