{"record":{"id":"5b71b1721c243036","repo":"jesseduffield/lazygit","slug":"dynamic-joined-stderr-of-failed-piped-commands","errorCode":null,"errorMessage":"<dynamic: joined stderr of failed piped commands>","messagePattern":"<dynamic: joined stderr of failed piped commands>","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/oscommands/os.go","lineNumber":274,"sourceCode":"\t\t// Without the rest of the pipeline to drain them, the commands we did\n\t\t// start could block forever writing to a full pipe.\n\t\tfor _, cmd := range cmds[:started] {\n\t\t\t_ = cmd.Process.Kill()\n\t\t}\n\t}\n\n\tfor i, cmd := range cmds[:started] {\n\t\tif err := cmd.Wait(); err != nil {\n\t\t\tc.Log.Error(err)\n\t\t}\n\n\t\tif stderrs[i].Len() > 0 {\n\t\t\tfinalErrors = append(finalErrors, stderrs[i].String())\n\t\t}\n\t}\n\n\tif len(finalErrors) > 0 {\n\t\treturn errors.New(strings.Join(finalErrors, \"\\n\"))\n\t}\n\treturn nil\n}\n\nfunc (c *OSCommand) CopyToClipboard(str string) error {\n\tescaped := strings.ReplaceAll(str, \"\\n\", \"\\\\n\")\n\ttruncated := utils.TruncateWithEllipsis(escaped, 40)\n\n\tmsg := utils.ResolvePlaceholderString(\n\t\tc.Tr.Log.CopyToClipboard,\n\t\tmap[string]string{\n\t\t\t\"str\": truncated,\n\t\t},\n\t)\n\tc.LogCommand(msg, false)\n\tif c.UserConfig().OS.CopyToClipboardCmd != \"\" {\n\t\tcmdStr := utils.ResolvePlaceholderString(c.UserConfig().OS.CopyToClipboardCmd, map[string]string{\n\t\t\t\"text\": c.Cmd.Quote(str),","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/commands/oscommands/os.go#L256-L292","documentation":"From OSCommand.PipeCommands in pkg/commands/oscommands/os.go:274. lazygit runs several commands in a pipeline (each stdout feeding the next stdin), and on failure collects each command's buffered stderr; if any accumulated, they are joined with newlines into a single error. This identifies which pipeline stage(s) failed.","triggerScenarios":"PipeCommands is used for pipelines like 'git cat-file --batch' | 'git apply' style chains (e.g. copy filename to clipboard pipelines or diff piping). Any stage exiting non-zero that wrote to stderr contributes its stderr to the joined error.","commonSituations":"Corrupt object store making an early cat-file stage fail, patch application failure in a later stage, locale/environment differences altering git stderr output inside the pipe.","solutions":["Split the joined error by newlines; each block is one pipeline stage's stderr, in pipeline order","Reconstruct the pipeline manually in a shell to see which stage fails","Run 'git fsck' if object corruption is suspected","Fix the environment/tool issue named in the stderr text"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := osCommand.PipeCommands(cmds...); err != nil {\n    for _, stage := range strings.Split(err.Error(), \"\\n\") {\n        log.Printf(\"pipeline stage stderr: %s\", stage)\n    }\n    return err\n}","preventionTips":["Reproduce pipelines manually stage-by-stage when they fail","Run 'git fsck' periodically on repos used with piped git plumbing","Keep the same locale/environment for lazygit as for interactive git"],"tags":["git","subprocess","pipeline","stderr"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}