nikivdev/code · error

SSH mode is forced but no key is available. Run `f ssh setup

Error message

SSH mode is forced but no key is available. Run `f ssh setup` or `f ssh unlock` (error: {})

What it means

clone_git_like enforces SSH policy before cloning: if ssh_mode() reports Force but no SSH identities exist, it attempts to generate/ensure a default key; if that also fails, it bails with this message including the underlying error. It tells the user exactly which commands restore an available key.

Source

Thrown at src/repos.rs:70

        Some(ReposAction::HomeBranchStatus(opts)) => run_home_branch_status(opts),
        Some(ReposAction::BootstrapHomeBranch(opts)) => run_bootstrap_home_branch(opts),
        Some(ReposAction::MigrateHomeBranch(opts)) => run_migrate_home_branch(opts),
        Some(ReposAction::Create(opts)) => publish::run_github(opts),
        Some(ReposAction::Capsule(opts)) => repo_capsule::run_capsule(opts),
        Some(ReposAction::Alias(cmd)) => repo_capsule::run_alias(cmd),
        None => fuzzy_select_repo(),
    }
}

/// Clone into the current working directory (git clone style destination behavior).
pub fn clone_git_like(opts: CloneOpts) -> Result<()> {
    ssh::ensure_ssh_env();
    let mode = ssh::ssh_mode();
    if matches!(mode, ssh::SshMode::Force) && !ssh::has_identities() {
        match ssh_keys::ensure_default_identity(24) {
            Ok(()) => {}
            Err(err) => {
                bail!(
                    "SSH mode is forced but no key is available. Run `f ssh setup` or `f ssh unlock` (error: {})",
                    err
                );
            }
        }
    }

    let clone_url = resolve_git_like_clone_url(&opts.url)?;
    let mut cmd = Command::new("git");
    cmd.arg("clone").arg(&clone_url);
    if let Some(dir) = opts.directory {
        cmd.arg(dir);
    }

    let status = cmd
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())

View on GitHub (pinned to a747e741ae)

Solutions

  1. Run `f ssh setup` to create/configure a default SSH key
  2. Run `f ssh unlock` if you have an existing encrypted key that needs unlocking
  3. Verify `ssh-add -l` shows a key; start the agent (`eval "$(ssh-agent)"`) and add the key
  4. Test with `ssh -T git@github.com` to confirm SSH works before cloning

Example fix

// before
f clone git@github.com:org/repo.git  // fails: forced SSH, no key
// after
f ssh setup
f clone git@github.com:org/repo.git
Defensive patterns

Strategy: validation

Validate before calling

const { execSync } = require("child_process");
function hasSshIdentity() {
  try { return execSync("ssh-add -l", { stdio: ["ignore", "pipe", "ignore"] }).toString().trim().length > 0; }
  catch { return false; }
}
if (!hasSshIdentity()) throw new Error("no SSH identity; run `f ssh setup` before cloning");

Try / catch

try {
  run(["f", "clone", url]);
} catch (e) {
  if (String(e).includes("SSH mode is forced but no key")) {
    console.error("Run `f ssh setup` or `f ssh unlock`, then retry the clone.");
  } else throw e;
}

Prevention

When it happens

Trigger: `f` clone with SSH mode forced while `ssh::has_identities()` is false AND ssh_keys::ensure_default_identity(24) returns Err (e.g. ssh-agent unavailable, keychain unlock failure, permission error writing the key).

Common situations: Fresh machine with no SSH key set up; agent not running / key not loaded after reboot; encrypted key that was never unlocked; forced SSH config pointing at Git remotes on a machine without keys.

Related errors


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