{"record":{"id":"f414fc25c9b6835f","repo":"jesseduffield/lazygit","slug":"dynamic-combined-stdout-stderr-of-failed-command","errorCode":null,"errorMessage":"<dynamic: combined stdout/stderr of failed command>","messagePattern":"<dynamic: combined stdout/stderr of failed command>","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/oscommands/cmd_obj_runner.go","lineNumber":213,"sourceCode":"\n\tself.log.Infof(\"%s (%s)\", cmdObj.ToString(), time.Since(t))\n\n\treturn nil\n}\n\nfunc (self *cmdObjRunner) logCmdObj(cmdObj *CmdObj) {\n\tself.guiIO.logCommandFn(cmdObj.ToString(), true)\n}\n\nfunc sanitisedCommandOutput(output []byte, err error) (string, error) {\n\toutputString := string(output)\n\tif err != nil {\n\t\t// errors like 'exit status 1' are not very useful so we'll create an error\n\t\t// from the combined output\n\t\tif outputString == \"\" {\n\t\t\treturn \"\", utils.WrapError(err)\n\t\t}\n\t\treturn outputString, errors.New(outputString)\n\t}\n\treturn outputString, nil\n}\n\ntype cmdHandler struct {\n\tstdoutPipe io.Reader\n\tstdinPipe  io.Writer\n\tclose      func() error\n\t// wait blocks until the child process exits. Needed as a separate\n\t// field because the pty path on Windows spawns via CreateProcess and\n\t// never runs *exec.Cmd.Start — so cmd.Wait wouldn't work there.\n\twait func() error\n}\n\nfunc (self *cmdObjRunner) runAndStream(cmdObj *CmdObj) error {\n\treturn self.runAndStreamAux(cmdObj, func(handler *cmdHandler, cmdWriter io.Writer) {\n\t\t_, _ = io.Copy(cmdWriter, handler.stdoutPipe)\n\t})","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/commands/oscommands/cmd_obj_runner.go#L195-L231","documentation":"Produced by sanitisedCommandOutput in pkg/commands/oscommands/cmd_obj_runner.go:213. When a shell command fails, the raw error from os/exec (e.g. 'exit status 1') is uninformative, so lazygit replaces it with the command's combined stdout/stderr captured as the error message. This is a deliberate sanitization: the dynamic message IS the command output you need to read.","triggerScenarios":"Any CmdObj run through a runner that uses sanitisedCommandOutput (RunCredential, RunAndDetectCredentialRequest, etc.) where the child process exits non-zero and produced output. Examples: 'git push' rejected by remote, 'git fetch' network failure, credential helper failure — the error surfaces the combined output.","commonSituations":"Pushing to a branch protected on the remote, authentication expiry mid-session, ssh host key changes, disk-full during git gc, any upstream git CLI failure surfaced inside the lazygit UI.","solutions":["Read the error text itself: it is the real git/shell output, which usually names the actual problem (auth, permissions, network)","Reproduce outside lazygit with the same git command to see full context","Fix the underlying cause (credentials, remote permissions, network) rather than handling this wrapper error","In custom code, check cmdObj error with errors.As / string inspection only if you need branching on failure"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"output, err := cmdObjRunner.RunCredential(...)\nif err != nil {\n    // err.Error() IS the combined stdout/stderr; log and surface it verbatim\n    log.Printf(\"git failed: %s\", err)\n    return err\n}","preventionTips":["Read the error body — it already contains the real git output","Keep credentials and remote permissions healthy so push/fetch succeed","Enable lazygit's command log to correlate failures with exact command lines"],"tags":["git","subprocess","error-wrapping","os-commands"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}