Skip to content

[Detail Bug] CLI: Empty or malformed $SHELL produces opaque "unsupported shell" error for completions #308

@detail-app

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_5f375fe3-a706-4e9a-a6f7-800f2439b3f6/bugs/bug_50cf379c-4f50-4ec2-94e5-3dc1b7e9f45a

Introduced in #182 by @sachiniyer on Mar 11, 2026

Summary

  • Context: The detect_shell() function in src/commands/completions.rs extracts the shell name from the $SHELL environment variable for auto-detection when no shell argument is provided.
  • Bug: When $SHELL is set but empty (SHELL=""), or contains only a path with trailing slashes, rsplit('/').next() returns an empty string. The resulting error message "unsupported shell: " shows no visible shell name.
  • Actual vs. expected: With SHELL="" (empty string, but variable IS set), the error "unsupported shell: " is shown instead of a clear message indicating the SHELL variable is empty or malformed.
  • Impact: Users receive an opaque error message that doesn't identify the root cause, unlike other error paths in this codebase that clearly identify missing/invalid input.

Code with Bug

fn detect_shell() -> Result<String> {
    let shell = env::var("SHELL").context("could not detect shell from $SHELL")?;
    // $SHELL is e.g. "/bin/zsh" — take the basename
    let name = shell.rsplit('/').next().unwrap_or(&shell); // <-- BUG 🔴 can return "" for empty/malformed $SHELL
    Ok(name.to_lowercase())
}

Explanation

  • env::var("SHELL") distinguishes only between unset (Err) and set (Ok), but does not validate that the value is non-empty / well-formed.
  • For SHELL="", "".rsplit('/').next() returns Some(""), which lowercases to "" and propagates into the completions shell parsing, resulting in an error like: unsupported shell: (supported: ...).
  • Similarly, values ending in / can yield an empty basename and produce the same opaque error.

Codebase Inconsistency

Other code paths validate/trim empty input and trailing slashes (e.g. src/utils/repos.rs checks for empty parts; src/utils/datetime.rs trims; src/utils/git.rs trims trailing slashes), but detect_shell() does not, leading to inconsistent and less-informative error messages.

Recommended Fix

Trim and validate $SHELL before extracting the basename, and explicitly error on empty/unextractable shell names (including after trimming trailing slashes), e.g.:

  • let shell = shell.trim(); if shell.is_empty() { bail!("$SHELL is empty"); }
  • let shell = shell.trim_end_matches('/'); ...; if name.is_empty() { bail!("could not extract shell name from $SHELL: {shell}"); }

History

This bug was introduced in commit fd339df.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions