nikivdev/code · error

`gh auth token` returned empty token

Error message

`gh auth token` returned empty token

What it means

After `gh auth token` exits successfully, get_gh_token trims stdout and rejects an empty result. A zero exit with no token means gh's stored credential state is inconsistent, and using an empty token would produce confusing upstream auth failures.

Source

Thrown at src/pr_edit.rs:405

        entry.public.state = SyncState::Error;
        entry.public.last_error = Some(err);
    }

    async fn get_gh_token(&self) -> Result<String> {
        if let Some(t) = self.gh_token.read().await.clone() {
            return Ok(t);
        }

        let out = Command::new("gh")
            .args(["auth", "token"])
            .output()
            .context("failed to run `gh auth token`")?;
        if !out.status.success() {
            bail!("`gh auth token` failed; run `gh auth login`");
        }
        let token = String::from_utf8_lossy(&out.stdout).trim().to_string();
        if token.is_empty() {
            bail!("`gh auth token` returned empty token");
        }

        *self.gh_token.write().await = Some(token.clone());
        Ok(token)
    }

    async fn write_status_json(&self) -> Result<()> {
        let snapshot = self.status_snapshot().await;
        let json = serde_json::to_string_pretty(&snapshot)?;

        let tmp = self.dir.join(format!(".{STATUS_FILENAME}.tmp"));
        let out = self.dir.join(STATUS_FILENAME);
        std::fs::write(&tmp, json)?;
        // Best-effort atomic replace.
        let _ = std::fs::rename(&tmp, &out);
        Ok(())
    }

View on GitHub (pinned to a747e741ae)

Solutions

  1. Re-authenticate: `gh auth login` (or `gh auth login --with-token < token.txt`).
  2. Check `gh auth token` output directly and inspect `gh auth status` for inconsistencies.
  3. Ensure you are using an official, current gh binary — not a wrapper that prints nothing.

Example fix

// before
$ gh auth token
(no output, exit 0)
$ f pr-edit ...
// `gh auth token` returned empty token

// after
$ gh auth login
$ gh auth token
ghp_xxxx
$ f pr-edit ...
Defensive patterns

Strategy: try-catch

Validate before calling

let out = std::process::Command::new("gh")
    .args(["auth", "token"])
    .output()?;
let token = String::from_utf8_lossy(&out.stdout).trim().to_string();
if !out.status.success() || token.is_empty() {
    eprintln!("gh returned no usable token; re-run `gh auth login`");
}

Try / catch

match pr_edit_result {
    Err(e) if e.to_string().contains("empty token") => {
        eprintln!("gh credential store is inconsistent; run `gh auth login` again");
    }
    other => other?,
}

Prevention

When it happens

Trigger: gh exits 0 but prints nothing to stdout — e.g. a hosts.yml entry exists without a stored token, or an old/patched gh version emits the token to a different stream.

Common situations: Corrupt gh credential store after partial logout; gh version mismatch where `gh auth token` prints to stderr; wrapper scripts around gh that swallow output.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/3fc930df1106e2a3. Report an issue: GitHub.