Hmbown/CodeWhale · error · std::io::Error
NotFound
NotFound
Error message
gh not found
What it means
The /project share flow writes an HTML session export to a temp file and uploads it as a public GitHub Gist via the `gh` CLI. Gh::command() resolves gh on PATH by probing candidates with --version (cached per process); when it returns None, upload_gist maps that to this NotFound error. The gist upload is therefore entirely dependent on gh being installed, authenticated, and visible to the codewhale process.
Source
Thrown at crates/tui/src/commands/groups/project/share.rs:164
}
/// Write HTML to a secure temp file and keep it alive for upload.
fn write_temp_html(html: &str) -> Result<tempfile::NamedTempFile, String> {
let mut tmp = tempfile::Builder::new()
.prefix("codewhale-share-")
.suffix(".html")
.tempfile()
.map_err(|e| format!("{e}"))?;
tmp.write_all(html.as_bytes()).map_err(|e| format!("{e}"))?;
Ok(tmp)
}
/// Upload a file as a GitHub Gist using the `gh` CLI.
async fn upload_gist(path: &Path) -> Result<String, String> {
let path_owned = path.to_path_buf();
let output = tokio::task::spawn_blocking(move || {
let mut cmd = crate::dependencies::Gh::command()
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, "gh not found"))?;
cmd.args([
"gist",
"create",
"--public",
path_owned.to_string_lossy().as_ref(),
"--filename",
"session-export.html",
"--desc",
"codewhale Session Export",
])
.output()
})
.await
.map_err(|join_err| format!("gh gist create panicked: {join_err}"))?
.map_err(|e| format!("Failed to run `gh gist create`: {e}"))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);View on GitHub (pinned to 0c42157ee5)
Solutions
- Install GitHub CLI: brew install gh, winget install GitHub.cli, or see cli.github.com
- Confirm `gh --version` and `gh auth login` succeed in the same environment that launches codewhale, then restart the TUI (probe result is cached per process)
- Fix PATH so the gh binary's directory is included for the launching process, not only your interactive shell
Example fix
# before codewhale /project share # NotFound: gh not found # after brew install gh && gh auth login exec $SHELL # restart so the probe re-runs codewhale /project share
Defensive patterns
Strategy: validation
Validate before calling
if !crate::dependencies::Gh::available() {
return Err("GitHub CLI (gh) is required to share: install from cli.github.com and run gh auth login".into());
} Type guard
fn share_available() -> bool {
crate::dependencies::Gh::command().is_some()
} Prevention
- Check Gh::available() before offering the share action in the UI
- Install and authenticate gh (gh auth login) once per machine
- Restart the TUI after installing gh — resolution is cached per process
When it happens
Trigger: Running the share/upload command on a machine without GitHub CLI installed, with gh present but not on the PATH of the codewhale process (launched from a GUI, service, or container), or with a broken gh install whose --version probe fails so resolution caches None for the process lifetime.
Common situations: Fresh machines; gh installed via brew/winget but the shell or TUI was not restarted; Windows gh under %LOCALAPPDATA%\GitHub CLI missing from system PATH; minimal dev containers without gh.
Understand the failure class
Background: "Not Found" / HTTP 404 Errors: What They Mean and How to Fix Them Across Libraries — this error's family across 6 libraries.
Related errors
- `gh` CLI not found on PATH. Install GitHub CLI (https://cli.
- gh pr view #{number} failed: {stderr}
- gh pr diff #{number} failed: {stderr}
- NotFound
- tmux attach unavailable
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/767a91c2b51344b9.
Report an issue: GitHub.