d2lang/d2 · error

error reading from stdin: %w

Error message

error reading from stdin: %w

What it means

readInput reads the sketch/pad input; when the path is "-" it reads from stdin via io.ReadAll(os.Stdin). If the stdin read fails, the error is wrapped as "error reading from stdin".

Source

Thrown at d2cli/play.go:56

	if err != nil {
		return err
	}

	encoded, err := urlenc.Encode(fileRaw)
	if err != nil {
		return err
	}

	url := fmt.Sprintf("https://play.d2lang.com/?script=%s&sketch=%d&theme=%d&", encoded, sketchNumber, theme)
	openBrowser(ctx, ms, url)
	return nil
}

func readInput(filepath string) (string, error) {
	if filepath == "-" {
		data, err := io.ReadAll(os.Stdin)
		if err != nil {
			return "", fmt.Errorf("error reading from stdin: %w", err)
		}
		return string(data), nil
	}

	data, err := os.ReadFile(filepath)
	if err != nil {
		return "", xmain.UsageErrorf("%s", err.Error())
	}
	return string(data), nil
}

func openBrowser(ctx context.Context, ms *xmain.State, url string) {
	ms.Log.Info.Printf("opening playground: %s", url)

	err := xbrowser.Open(ctx, ms.Env, url)
	if err != nil {
		ms.Log.Warn.Printf("failed to open browser to %v: %v", url, err)
	}

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Pipe content into the command: `cat sketch.d2 | d2 play -`
  2. Or pass a real file path instead of "-"
  3. Check that the upstream command in the pipeline succeeds

Example fix

// before
d2 play -          # no stdin provided
// after
cat sketch.d2 | d2 play -
Defensive patterns

Strategy: try-catch

Validate before calling

stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) != 0 {
	// stdin is a terminal, not a pipe — provide a file or pipe input
}

Try / catch

input, err := readInput(path)
if err != nil {
	return fmt.Errorf("pipe input: cat sketch.d2 | d2 play - (%v)", err)
}

Prevention

When it happens

Trigger: Running the play command with "-" as the input path (e.g. `d2 play -`) while stdin is closed, not piped, or the pipe writer errored/closed mid-stream.

Common situations: Running `d2 play -` in an interactive terminal without piping input,CI jobs where stdin is /dev/null or closed, or upstream command in a pipe failing and closing the pipe early.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/3f87ff3f21532db4. Report an issue: GitHub.