getsops/sops · error
failed to execute command %s: %w
Error message
failed to execute command %s: %w
What it means
The command configured in SOPS_AGE_SSH_PRIVATE_KEY_CMD was parsed successfully and executed via exec.Command(...).Output(), but it returned a non-zero exit status or failed to start. SOPS wraps that error, so the underlying message (e.g. 'exit status 1' or 'executable file not found') is chained in %w. This means SOPS could not obtain age identities from that command.
Source
Thrown at age/keysource.go:313
}
// getOutputFromCmd executes a shell command provided in param 'cmdString',
// optionally adding env vars provided in param 'envVars',
// and returns the command's output and error
func getOutputFromCmd(cmdString string, envVars []string) ([]byte, error) {
var out []byte
args, err := shlex.Split(cmdString)
if err != nil {
return nil, fmt.Errorf("failed to parse command %s: %w", cmdString, err)
}
cmd := exec.Command(args[0], args[1:]...)
if envVars != nil {
cmd.Env = append(os.Environ(), envVars[0:]...)
}
out, err = cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to execute command %s: %w", cmdString, err)
}
return out, nil
}
// loadAgeSSHIdentity attempts to load age SSH identities in this order:
// 1. An SSH private key from the SopsAgeSshPrivateKeyFileEnv environment variable.
// 2. An SSH private key returned by executing the command from the
// SopsAgeSshPrivateKeyCmdEnv environment variable
// 3. `~/.ssh/id_ed25519` or `~/.ssh/id_rsa`.
// If no age SSH identity is found, it will return nil.
func (key *MasterKey) loadAgeSSHIdentities() ([]age.Identity, []string, errSet) {
var identities []age.Identity
var unusedLocations []string
var errs errSet
sshKeyFilePath, ok := os.LookupEnv(SopsAgeSshPrivateKeyFileEnv)
if ok {View on GitHub (pinned to 13442bb981)
Solutions
- Run the command from SOPS_AGE_SSH_PRIVATE_KEY_CMD directly in a shell and check its exit status/output; fix whatever it reports (missing key, locked store, etc.).
- Verify the binary exists and is executable: command -v <binary> and check the PATH in the environment running sops.
- If it uses ssh-agent, ensure the agent is running and the identity is added (ssh-add -l).
- For pass/gopass-backed commands, initialize/unlock the store and confirm the exact entry name exists.
- Wrap the command in a script that logs stderr so the real failure is visible, then point the env var at it.
Example fix
// before export SOPS_AGE_SSH_PRIVATE_KEY_CMD="pass show age-key" # entry doesn't exist // failed to execute command pass show age-key: exit status 1 // after pass ls | grep age-key # confirm the entry name export SOPS_AGE_SSH_PRIVATE_KEY_CMD="pass show age/identity" sops -d secrets.enc.yaml
Defensive patterns
Strategy: try-catch
Validate before calling
// shell: pre-flight the command exactly as sops would run it
CMD="$SOPS_AGE_SSH_PRIVATE_KEY_CMD"
$CMD > /dev/null || { echo "key command failed: $?"; exit 1; }
command -v "${CMD%% *}" >/dev/null || { echo "binary not on PATH"; exit 1; } Try / catch
out, err := exec.Command("sops", "-d", file).Output()
var ee *exec.ExitError
if errors.As(err, &ee) && strings.Contains(string(ee.Stderr), "failed to execute command") {
return fmt.Errorf("SOPS_AGE_SSH_PRIVATE_KEY_CMD binary failed; check agent/store: %w", err)
} Prevention
- Run the key command manually on each host before deploying sops workflows.
- Ensure ssh-agent is running and identities loaded (ssh-add -l) when the command uses agent keys.
- Provision secret-store entries (pass/gopass) as part of machine bootstrap.
- Check PATH for non-interactive contexts (cron, systemd, CI) — login shell PATH often differs.
- Capture stderr in wrapper scripts so failures are diagnosable.
When it happens
Trigger: getOutputFromCmd runs the SOPS_AGE_SSH_PRIVATE_KEY_CMD binary; error occurs if the binary is missing, not executable, or exits non-zero (no matching key in ssh-agent, pass/gopass entry missing, wrong passphrase).
Common situations: ssh-agent not running or key not loaded; pass store entry absent on a new machine; typo in binary name; CI environment lacking the secret store; script failing due to missing HOME or TTY.
Related errors
- failed to parse command %s: %w
- failed to open %s file: %w
- user config directory could not be determined: %w
- failed to parse input as age key from age plugin: %w
- incorrect passphrase
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/8cd3f5f54463032a.
Report an issue: GitHub.