apache/beam · error
render DOT failed
Error message
render DOT failed
What it means
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".
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.
Example fix
// before
f, _ := os.Create("graph.dot")
dot.Render(p, f) // fails if disk full, cause hidden
// after
var buf bytes.Buffer
if err := dot.Render(p, &buf); err != nil {
return fmt.Errorf("render: %w", err)
}
os.WriteFile("graph.dot", buf.Bytes(), 0644) Defensive patterns
Strategy: fallback
Validate before calling
func writable(w io.Writer) error {
if f, ok := w.(*os.File); ok {
if _, err := f.Stat(); err != nil {
return err
}
}
return nil
} Type guard
if f, ok := w.(*os.File); ok {
if _, err := f.Stat(); err != nil {
// writer is unusable; don't attempt Render
}
} Try / catch
var buf bytes.Buffer
if err := dot.Render(p, &buf); err != nil {
return fmt.Errorf("render DOT failed: %w", err)
}
if _, err := w.Write(buf.Bytes()); err != nil {
return fmt.Errorf("write DOT failed: %w", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- bucket must not be empty
- empty chunk
- error decoding bool
- error encoding bool
- A schema is required to write non-schema'd data.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/d050f5a4f538ca21.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/util/dot/dot.go:129
for _, node := range nodes {
if seen[node] {
continue
}
seen[node] = true
err := nodeTmpl.Execute(w, struct{ Name, Label string }{node.String(), uniqNodes[node].String()})
if err != nil {
return err
}
}
for _, edge := range edges {
e := fmt.Sprintf("%d: %s", edge.ID(), edge.Op)
label := fmt.Sprint(edge.Op)
if name := path.Base(edge.Name()); name != label {
label = fmt.Sprintf("%s\n%s", edge.Op, name)
}
if err := edgeDefnTmpl.Execute(w, struct{ Name, Label string }{e, label}); err != nil {
return errors.Wrap(err, "render DOT failed")
}
for _, ib := range edge.Input {
err := edgeTmpl.Execute(w, struct{ From, To string }{ib.From.String(), e})
if err != nil {
return errors.Wrap(err, "render DOT failed")
}
}
for _, ob := range edge.Output {
uniqNodes[ob.To].From = ob
err := edgeTmpl.Execute(w, struct{ From, To string }{e, ob.To.String()})
if err != nil {
return errors.Wrap(err, "render DOT failed")
}
}
}
w.Write([]byte(footer))
return nil
}View on GitHub (pinned to 12126d8942)