d2lang/d2 · error
multiboard output cannot be written to stdout
Error message
multiboard output cannot be written to stdout
What it means
When the compiled diagram has subboards (layers/scenarios/steps), render produces a multiboard output consisting of multiple files. Because stdout ('-') can only hold one document, render rejects writing multiboard output to stdout with this error.
Source
Thrown at d2cli/main.go:834
if !ok {
return in, nil
}
return postProcessor.PostProcess(ctx, in)
}
func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plugin d2plugin.Plugin, opts d2svg.RenderOpts, inputPath, outputPath string, bundle, forceAppendix bool, browser playwright.Browser, ruler *textmeasure.Ruler, diagram *d2target.Diagram, ext exportExtension, asciiMode string) ([][]byte, error) {
if diagram.Name != "" {
ext := filepath.Ext(outputPath)
outputPath = strings.TrimSuffix(outputPath, ext)
outputPath = filepath.Join(outputPath, diagram.Name)
outputPath += ext
}
boardOutputPath := outputPath
if len(diagram.Layers) > 0 || len(diagram.Scenarios) > 0 || len(diagram.Steps) > 0 {
if outputPath == "-" {
// TODO it can if composed into one
return nil, fmt.Errorf("multiboard output cannot be written to stdout")
}
// Boards with subboards must be self-contained folders.
ext := filepath.Ext(boardOutputPath)
boardOutputPath = strings.TrimSuffix(boardOutputPath, ext)
os.RemoveAll(boardOutputPath)
boardOutputPath = filepath.Join(boardOutputPath, "index")
boardOutputPath += ext
}
layersOutputPath := outputPath
if len(diagram.Scenarios) > 0 || len(diagram.Steps) > 0 {
ext := filepath.Ext(layersOutputPath)
layersOutputPath = strings.TrimSuffix(layersOutputPath, ext)
layersOutputPath = filepath.Join(layersOutputPath, "layers")
layersOutputPath += ext
}
scenariosOutputPath := outputPath
if len(diagram.Layers) > 0 || len(diagram.Steps) > 0 {View on GitHub (pinned to 0d69dca6f5)
Solutions
- Provide a real output file path so boards are written as a folder (dir/index files)
- Remove the layers/scenarios/steps if a single-board stdout render was intended
- Flatten the diagram to a single board before rendering to stdout
Example fix
// before d2 --board . input.d2 - | tee out.svg // multiboard diagram // after d2 input.d2 outdir/ # or render a single board to stdout
Defensive patterns
Strategy: validation
Validate before calling
// before writing to stdout, ensure single board
if outputPath == "-" && (len(diagram.Layers) > 0 || len(diagram.Scenarios) > 0 || len(diagram.Steps) > 0) {
return errors.New("provide a file path for multiboard output")
} Try / catch
if err := render(...); err != nil && strings.Contains(err.Error(), "multiboard") {
// retry with a directory output path instead of "-"
} Prevention
- Never use '-' as output path for diagrams that define layers/scenarios/steps
- In scripts, default to a temp directory output when board count > 1
- Check for subboards before choosing stdout mode
When it happens
Trigger: Running d2 with output path '-' (stdout) on a diagram containing layers, scenarios, or steps, and an output format that is not a single composed document.
Common situations: Piping d2 output in shell scripts while the .d2 file defines layers, forgetting that multiboard needs a directory output path.
Related errors
- %s is not a supported format. Supported formats are: %s
- failed to fully compile (partial render written) %s: %w
- failed to compile %s: %w
- render target "%s" not found
- no color stops in gradient
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/c86ea3f9a18d212b.
Report an issue: GitHub.