{"record":{"id":"d050f5a4f538ca21","repo":"apache/beam","slug":"render-dot-failed","errorCode":null,"errorMessage":"render DOT failed","messagePattern":"render DOT failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/util/dot/dot.go","lineNumber":129,"sourceCode":"\tfor _, node := range nodes {\n\t\tif seen[node] {\n\t\t\tcontinue\n\t\t}\n\t\tseen[node] = true\n\t\terr := nodeTmpl.Execute(w, struct{ Name, Label string }{node.String(), uniqNodes[node].String()})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, edge := range edges {\n\t\te := fmt.Sprintf(\"%d: %s\", edge.ID(), edge.Op)\n\t\tlabel := fmt.Sprint(edge.Op)\n\t\tif name := path.Base(edge.Name()); name != label {\n\t\t\tlabel = fmt.Sprintf(\"%s\\n%s\", edge.Op, name)\n\t\t}\n\t\tif err := edgeDefnTmpl.Execute(w, struct{ Name, Label string }{e, label}); err != nil {\n\t\t\treturn errors.Wrap(err, \"render DOT failed\")\n\t\t}\n\t\tfor _, ib := range edge.Input {\n\t\t\terr := edgeTmpl.Execute(w, struct{ From, To string }{ib.From.String(), e})\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"render DOT failed\")\n\t\t\t}\n\t\t}\n\t\tfor _, ob := range edge.Output {\n\t\t\tuniqNodes[ob.To].From = ob\n\t\t\terr := edgeTmpl.Execute(w, struct{ From, To string }{e, ob.To.String()})\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"render DOT failed\")\n\t\t\t}\n\t\t}\n\t}\n\tw.Write([]byte(footer))\n\treturn nil\n}","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/util/dot/dot.go#L111-L147","documentation":"dot.Render writes a Beam pipeline graph as Graphviz DOT text using Go text/template execution against node/edge templates. If any template Execute call fails (rare — template parse is checked at init, so failures here are writer errors or internal template bugs), the error is wrapped as \"render DOT failed\".","triggerScenarios":"Calling dot.Render(p, w) where the underlying io.Writer returns an error during template execution (e.g. closed file, disk full, broken pipe), or an internal template data mismatch causes Execute to fail.","commonSituations":"Users render pipeline DOT to a file on a full filesystem, to a network mount that dropped, or piping to a process that exited early (os/exec pipe closed); also when generating DOT from a harness where the writer is an HTTP body that errored.","solutions":["Unwrap with errors.Unwrap / %v on the cause to see the underlying writer error, then fix that (disk space, permissions, connection).","Verify the io.Writer passed to dot.Render is open and writable for the duration of the call.","If piping DOT output, ensure the downstream process (e.g. `dot -Tsvg`) is alive and reading; check its stderr.","Render to an in-memory bytes.Buffer first, then write the buffer to the destination with explicit error handling."],"exampleFix":"// before\nf, _ := os.Create(\"graph.dot\")\ndot.Render(p, f) // fails if disk full, cause hidden\n\n// after\nvar buf bytes.Buffer\nif err := dot.Render(p, &buf); err != nil {\n    return fmt.Errorf(\"render: %w\", err)\n}\nos.WriteFile(\"graph.dot\", buf.Bytes(), 0644)","handlingStrategy":"fallback","validationCode":"func writable(w io.Writer) error {\n    if f, ok := w.(*os.File); ok {\n        if _, err := f.Stat(); err != nil {\n            return err\n        }\n    }\n    return nil\n}","typeGuard":"if f, ok := w.(*os.File); ok {\n    if _, err := f.Stat(); err != nil {\n        // writer is unusable; don't attempt Render\n    }\n}","tryCatchPattern":"var buf bytes.Buffer\nif err := dot.Render(p, &buf); err != nil {\n    return fmt.Errorf(\"render DOT failed: %w\", err)\n}\nif _, err := w.Write(buf.Bytes()); err != nil {\n    return fmt.Errorf(\"write DOT failed: %w\", err)\n}","preventionTips":["Render to a bytes.Buffer first, then persist, so template failures never hit a fragile writer.","Check disk space and file permissions before rendering large pipeline graphs.","When piping to `dot`, verify the child process stays alive and consumes output.","Close writers only after Render returns, not concurrently."],"tags":["go","apache-beam","graphviz","template","io"],"backgroundTag":"file-write-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}