{"record":{"id":"5d9a0a0d55d26b58","repo":"rancher/rancher","slug":"failed-to-read-chart-w","errorCode":null,"errorMessage":"failed to read chart: %w","messagePattern":"failed to read chart: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/codegen/buildconfig/chart_writer.go","lineNumber":43,"sourceCode":"\t\treturn errors.New(\"nil config\")\n\t}\n\tif err := w.processChart(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (w *ChartValuesWriter) processChart() error {\n\tif w.Chart == nil {\n\t\treturn errors.New(\"nil chart input\")\n\t}\n\tif w.Output == nil {\n\t\treturn errors.New(\"nil output\")\n\t}\n\n\tchartContent, err := io.ReadAll(w.Chart)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read chart: %w\", err)\n\t}\n\n\t// Parse chart as YAML to get line numbers for values\n\tvar chartRoot yaml.Node\n\tif err := yaml.Unmarshal(chartContent, &chartRoot); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse chart YAML: %w\", err)\n\t}\n\n\t// Collect line-based replacements instead of modifying the AST\n\treplacements := make(map[int]string) // line number -> new value\n\tif err := w.collectReplacements(&chartRoot, replacements); err != nil {\n\t\treturn fmt.Errorf(\"failed to collect replacements: %w\", err)\n\t}\n\n\t// Apply replacements line-by-line to preserve all formatting\n\treturn w.applyReplacements(chartContent, replacements)\n}\n","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/rancher/rancher/blob/932558d4e68565aff2d2f36e89ec4a391b06e7c5/pkg/codegen/buildconfig/chart_writer.go#L25-L61","documentation":"ChartValuesWriter.processChart reads the whole chart values stream with io.ReadAll (pkg/codegen/buildconfig/chart_writer.go:41-44); nil readers are rejected earlier at line 34, so this error means the reader itself failed mid-read. This is the buildconfig codegen tool that injects build.yaml-driven values into chart/values.yaml.","triggerScenarios":"w.Chart is a reader that errors during Read: a closed HTTP response body, a file closed or removed concurrently, a pipe whose writer failed, or a custom reader returning an error.","commonSituations":"CI codegen reading values.yaml from a substituted stream (curl pipe, process substitution) that terminates early; passing an already-closed *os.File; concurrent writers replacing the file mid-read.","solutions":["Ensure the reader is open and not already consumed before calling Run()","If reading from a file, open it fresh (os.Open) inside the run and check that error separately","Read the wrapped I/O error — it names the failing operation (file closed, broken pipe, etc.)","Buffer the input into memory first (bytes.Buffer/bytes.Reader) so I/O errors surface before processing"],"exampleFix":"// before\nw := &ChartValuesWriter{Config: cfg, Chart: resp.Body /* already closed */, Output: out}\nerr := w.Run()\n\n// after\ncontent, err := io.ReadAll(resp.Body)\nif err != nil { return err }\nw := &ChartValuesWriter{Config: cfg, Chart: bytes.NewReader(content), Output: out}\nerr = w.Run()","handlingStrategy":"validation","validationCode":"// buffer input first so I/O failures surface with context before Run()\ncontent, readErr := io.ReadAll(chartReader)\nif readErr != nil {\n\treturn fmt.Errorf(\"reading chart values: %w\", readErr)\n}\nw := &ChartValuesWriter{Config: cfg, Chart: bytes.NewReader(content), Output: out}","typeGuard":null,"tryCatchPattern":"if err := w.Run(); err != nil {\n\tif strings.Contains(err.Error(), \"failed to read chart\") {\n\t\t// input stream problem: verify the file/pipe feeding w.Chart is open\n\t}\n\treturn err\n}","preventionTips":["Open files fresh per run and close them after","Prefer bytes.Reader/bytes.Buffer inputs for codegen","Never reuse an already-consumed or closed response body"],"tags":["go","io","codegen","yaml"],"backgroundTag":null,"analyzedSha":"932558d4e68565aff2d2f36e89ec4a391b06e7c5","analyzedAt":"2026-08-16T04:37:02.125Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}