rtk-ai/rtk · error

tree command not found. Install it first: - macOS: brew inst

Error message

tree command not found. Install it first:
- macOS: brew install tree
- Ubuntu/Debian: sudo apt install tree
- Fedora/RHEL: sudo dnf install tree
- Arch: sudo pacman -S tree

What it means

rtk tree does not reimplement tree in Rust — it shells out to the external `tree` binary via resolved_command("tree") and first checks tool_exists("tree"). If no tree is on PATH it bails with per-distro install instructions before touching anything else.

Source

Thrown at src/cmds/system/tree.rs:16

//! tree command - proxy to native tree with token-optimized output
//!
//! This module proxies to the native `tree` command and filters the output
//! to reduce token usage while preserving structure visibility.
//!
//! Token optimization: automatically excludes noise directories via -I pattern
//! unless -a flag is present (respecting user intent).

use super::constants::NOISE_DIRS;
use crate::core::runner::{self, RunOptions};
use crate::core::utils::{resolved_command, tool_exists};
use anyhow::Result;

pub fn run(args: &[String], verbose: u8) -> Result<i32> {
    if !tool_exists("tree") {
        anyhow::bail!(
            "tree command not found. Install it first:\n\
             - macOS: brew install tree\n\
             - Ubuntu/Debian: sudo apt install tree\n\
             - Fedora/RHEL: sudo dnf install tree\n\
             - Arch: sudo pacman -S tree"
        );
    }

    let mut cmd = resolved_command("tree");

    let show_all = args.iter().any(|a| a == "-a" || a == "--all");
    let has_ignore = args.iter().any(|a| a == "-I" || a.starts_with("--ignore="));

    if !show_all && !has_ignore {
        let ignore_pattern = NOISE_DIRS.join("|");
        cmd.arg("-I").arg(&ignore_pattern);
    }

View on GitHub (pinned to d977e1c316)

Solutions

  1. Install tree: `brew install tree` (macOS), `sudo apt install tree` (Debian/Ubuntu), `sudo dnf install tree` (Fedora/RHEL), `sudo pacman -S tree` (Arch)
  2. In containers, bake it into the image: `RUN apt-get update && apt-get install -y --no-install-recommends tree`
  3. Without tree, approximate the overview: `rtk proxy fd --type d` or `rtk proxy ls -R | head -100`

Example fix

# before
rtk tree
# tree command not found. Install it first: ...

# after (Ubuntu/Debian)
sudo apt install tree && rtk tree
# Dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends tree
Defensive patterns

Strategy: validation

Validate before calling

bash:
if ! command -v tree >/dev/null 2>&1; then
  echo "tree missing — falling back to fd directory view" >&2
  exec rtk proxy fd --type d --max-depth 3
fi
rtk tree "$@"

Type guard

rust:
fn tree_available() -> bool {
    which::which("tree").is_ok()
}

Try / catch

rust:
match tree_cmd::run(&args, verbose) {
    Err(e) if e.to_string().contains("tree command not found") => {
        let st = std::process::Command::new("ls").arg("-R").status()?;
        std::process::exit(st.code().unwrap_or(1));
    }
    r => r?,
}

Prevention

When it happens

Trigger: `rtk tree` (or hook-rewritten `tree`) where tree is not installed: slim Docker images (node:slim, alpine, distroless), minimal CI runners, fresh macOS without brew, or a Nix/devshell that omits the package.

Common situations: Containerized dev/CI environments; ephemeral CI agents; hook-rewritten shells where plain `tree` from an agent silently becomes `rtk tree` and fails; portable dotfiles moved to a new machine.


AI-assisted analysis of rtk-ai/rtk@d977e1c316 (2026-08-16). Data as JSON: /api/errors/09ceedc39cba670d. Report an issue: GitHub.