{"record":{"id":"a65f0e674fb355f8","repo":"getsops/sops","slug":"failed-to-parse-command-s-w","errorCode":null,"errorMessage":"failed to parse command %s: %w","messagePattern":"failed to parse command (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"age/keysource.go","lineNumber":305,"sourceCode":"\tout[\"recipient\"] = key.Recipient\n\tout[\"enc\"] = key.EncryptedKey\n\treturn out\n}\n\n// TypeToIdentifier returns the string identifier for the MasterKey type.\nfunc (key *MasterKey) TypeToIdentifier() string {\n\treturn KeyTypeIdentifier\n}\n\n// getOutputFromCmd executes a shell command provided in param 'cmdString',\n// optionally adding env vars provided in param 'envVars',\n// and returns the command's output and error\nfunc getOutputFromCmd(cmdString string, envVars []string) ([]byte, error) {\n\tvar out []byte\n\n\targs, err := shlex.Split(cmdString)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse command %s: %w\", cmdString, err)\n\t}\n\tcmd := exec.Command(args[0], args[1:]...)\n\tif envVars != nil {\n\t\tcmd.Env = append(os.Environ(), envVars[0:]...)\n\t}\n\tout, err = cmd.Output()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to execute command %s: %w\", cmdString, err)\n\t}\n\n\treturn out, nil\n}\n\n// loadAgeSSHIdentity attempts to load age SSH identities in this order:\n// 1. An SSH private key from the SopsAgeSshPrivateKeyFileEnv environment variable.\n// 2. An SSH private key returned by executing the command from the\n// SopsAgeSshPrivateKeyCmdEnv environment variable\n// 3. `~/.ssh/id_ed25519` or `~/.ssh/id_rsa`.","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/age/keysource.go#L287-L323","documentation":"SOPS splits the SOPS_AGE_SSH_PRIVATE_KEY_CMD value with shlex so it can exec a command; if the command string is not valid shell syntax (unbalanced quotes, dangling backslash, etc.), shlex.Split fails and the command string is echoed back in the error. No command is executed in this case.","triggerScenarios":"loadIdentities -> loadAgeSSHIdentities reads SOPS_AGE_SSH_PRIVATE_KEY_CMD and getOutputFromCmd calls shlex.Split on it; any malformed quoting/token in the env var value produces this error before exec.","commonSituations":"Setting SOPS_AGE_SSH_PRIVATE_KEY_CMD=\"ssh-add -L\" with unbalanced quotes in shell config; wrapping the command in shell metacharacters (&&, |) that shlex treats as tokens; trailing backslashes from line continuations.","solutions":["Fix the SOPS_AGE_SSH_PRIVATE_KEY_CMD value so it parses as a simple argv list: balanced quotes, no shell operators like && or |.","Test the command string with a shell-free parser mindset: sops passes args[0] as the binary and the rest as arguments, no shell involved.","If you need pipes or redirection, point the var at a wrapper script and set SOPS_AGE_SSH_PRIVATE_KEY_CMD=\"/path/to/wrapper.sh\".","Export the variable in a clean form, e.g. export SOPS_AGE_SSH_PRIVATE_KEY_CMD='pass show age-identity', and verify with echo before running sops."],"exampleFix":"// before\nexport SOPS_AGE_SSH_PRIVATE_KEY_CMD=\"pass show age-key && cat\"\n// shlex treats && as an argument; parse error\n\n// after\nexport SOPS_AGE_SSH_PRIVATE_KEY_CMD=\"pass show age-key\"\n# or use a wrapper script for shell logic:\nexport SOPS_AGE_SSH_PRIVATE_KEY_CMD=\"$HOME/bin/age-key-cmd.sh\"","handlingStrategy":"validation","validationCode":"// shell: validate the command parses as simple argv before exporting\nexport SOPS_AGE_SSH_PRIVATE_KEY_CMD='pass show age-identity'\npython3 - <<'EOF'\nimport shlex, os\nargs = shlex.split(os.environ['SOPS_AGE_SSH_PRIVATE_KEY_CMD'])\nassert args and os.path.basename(args[0]), \"unparseable command\"\nprint(args)\nEOF","typeGuard":null,"tryCatchPattern":"if err := runSopsDecrypt(); err != nil {\n    if strings.Contains(err.Error(), \"failed to parse command\") {\n        return fmt.Errorf(\"SOPS_AGE_SSH_PRIVATE_KEY_CMD is not valid argv syntax: %w\", err)\n    }\n    return err\n}","preventionTips":["Never put shell operators (&&, |, ;, >) in SOPS_AGE_SSH_PRIVATE_KEY_CMD; sexec uses shlex argv, not a shell.","Use a wrapper script when you need shell logic, and point the env var at that script alone.","Keep the value in single quotes to prevent your own shell from mangling quotes.","Echo the variable in CI logs (redacted) to catch quoting drift between environments.","Test with a trivial command like 'echo hi' when debugging."],"tags":["age","shell","env-var","shlex"],"backgroundTag":"command-parse-failed","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}