rtk-ai/rtk · error

gt: no subcommand specified

Error message

gt: no subcommand specified

What it means

`run_other` in the gt (Graphite) filter handles `gt` subcommands that have no dedicated filtered path. It requires the first argument to name the subcommand; with an empty args slice there is nothing to forward to `gt`, so it bails with this error.

Solutions

  1. Provide the subcommand explicitly: e.g. `rtk gt sync`, `rtk gt submit`, `rtk gt branch`.
  2. For dedicated flows use the filtered entry points (`run_branch` etc.) or plain `gt` outside rtk if you need the interactive UI.
  3. Repair the calling wrapper/alias so arguments are forwarded verbatim to rtk.
  4. Make the dispatcher show gt usage/help on empty args rather than raising this error.

Example fix

// before
rtk gt

// after
rtk gt sync
Defensive patterns

Strategy: validation

Validate before calling

// guard before invoking the gt filter
const args: string[] = process.argv.slice(2);
if (args[0] !== "gt" || args.length < 2) {
  throw new Error("usage: rtk gt <subcommand> [args...]");
}

Try / catch

match rtk_gt(&args) {
    Ok(code) => std::process::exit(code),
    Err(e) if e.to_string().contains("no subcommand specified") => {
        eprintln!("usage: rtk gt <sync|submit|branch|...> [args...]");
        std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `rtk gt` (or the dispatcher routing to `run_other`) with an empty argument list — no subcommand such as `sync`, `submit`, or `checkout` is present.

Common situations: Typing `rtk gt` alone expecting gt's interactive TUI; a wrapper or alias that swallows arguments; automation passing an empty argv array; shell history expansion issues dropping the subcommand.

Understand the failure class

Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.

Related errors


AI-assisted analysis of rtk-ai/rtk@0924356b4c (2026-09-19). Data as JSON: /api/errors/445ad27b000f25d2. Report an issue: GitHub.

Appendix: source

Thrown at src/cmds/git/gt_cmd.rs:127

pub fn run_sync(args: &[String], verbose: u8) -> Result<i32> {
    run_gt_filtered(&["sync"], args, verbose, "gt_sync", filter_gt_sync)
}

pub fn run_restack(args: &[String], verbose: u8) -> Result<i32> {
    run_gt_filtered(&["restack"], args, verbose, "gt_restack", filter_gt_restack)
}

pub fn run_create(args: &[String], verbose: u8) -> Result<i32> {
    run_gt_filtered(&["create"], args, verbose, "gt_create", filter_gt_create)
}

pub fn run_branch(args: &[String], verbose: u8) -> Result<i32> {
    run_gt_filtered(&["branch"], args, verbose, "gt_branch", filter_identity)
}

pub fn run_other(args: &[OsString], verbose: u8) -> Result<i32> {
    if args.is_empty() {
        anyhow::bail!("gt: no subcommand specified");
    }

    let subcommand = args[0].to_string_lossy();
    let rest: Vec<String> = args[1..]
        .iter()
        .map(|a| a.to_string_lossy().into())
        .collect();

    // gt passes unknown subcommands to git, so "gt status" = "git status".
    // Route known git commands to RTK's git filters for token savings.
    match subcommand.as_ref() {
        "status" => crate::git_cmd::run(
            crate::git_cmd::GitCommand::Status,
            &rest,
            None,
            verbose,
            &[],
        ),

View on GitHub (pinned to 0924356b4c)