{"record":{"id":"300006e38c398423","repo":"d2lang/d2","slug":"failed-to-read-user-input-w","errorCode":null,"errorMessage":"failed to read user input: %w","messagePattern":"failed to read user input: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/png/png.go","lineNumber":112,"sourceCode":"\treturn startPlaywright(pw)\n}\n\nfunc InitPlaywrightWithPrompt() (Playwright, error) {\n\tif os.Getenv(\"CI\") != \"\" {\n\t\treturn InitPlaywright()\n\t}\n\n\t// Just try running first. This only works if drivers and browsers are already installed\n\tpw, err := playwright.Run()\n\tif err == nil {\n\t\treturn startPlaywright(pw)\n\t}\n\n\tfmt.Print(\"D2 needs to install Chromium v149.0.7827.55 to render non-SVG images. Continue? (y/N): \")\n\treader := bufio.NewReader(os.Stdin)\n\tresponse, err := reader.ReadString('\\n')\n\tif err != nil {\n\t\treturn Playwright{}, fmt.Errorf(\"failed to read user input: %w\", err)\n\t}\n\tresponse = strings.TrimSpace(strings.ToLower(response))\n\tif response != \"y\" && response != \"yes\" {\n\t\treturn Playwright{}, fmt.Errorf(\"chromium installation cancelled by user\")\n\t}\n\n\treturn InitPlaywright()\n}\n\ntype timeoutSetter interface {\n\tSetDefaultTimeout(float64)\n\tSetDefaultNavigationTimeout(float64)\n}\n\nfunc configureTimeout(target timeoutSetter) {\n\tseconds, ok := env.Timeout()\n\tif !ok {\n\t\treturn","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/lib/png/png.go#L94-L130","documentation":"InitPlaywrightWithPrompt reads the user's confirmation from stdin before installing Chromium; if bufio.Reader.ReadString('\\n') returns an error (most commonly EOF because stdin is closed or not a terminal), the error is wrapped with this message. It exists so interactive consent cannot silently fail.","triggerScenarios":"Calling InitPlaywrightWithPrompt() with stdin closed, redirected from an empty stream, or EOF reached before a newline; ReadString returning any non-nil error.","commonSituations":"Running in CI or scripts where stdin is /dev/null; piping commands without input; background services with no TTY.","solutions":["Provide stdin (e.g. echo y | d2 ...) when an interactive prompt is expected","Use InitPlaywright() directly for non-interactive/automated environments — the library already skips the prompt when CI env var is set","Set the CI environment variable to bypass the prompt","Check the wrapped cause (%w) — EOF usually means no interactive session"],"exampleFix":"// before\nd2 file.d2 out.png  # hangs/fails waiting on stdin in CI\n// after\nCI=1 d2 file.d2 out.png  # skips prompt, installs/uses chromium non-interactively","handlingStrategy":"fallback","validationCode":"stat, _ := os.Stdin.Stat()\ninteractive := (stat.Mode() & os.ModeCharDevice) != 0\nif !interactive { os.Setenv(\"CI\", \"1\") }","typeGuard":"func stdinIsTTY() bool { st, _ := os.Stdin.Stat(); return (st.Mode() & os.ModeCharDevice) != 0 }","tryCatchPattern":"pw, err := InitPlaywrightWithPrompt()\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to read user input\") {\n        return fallbackToSVG() // no interactive stdin\n    }\n    return err\n}","preventionTips":["Set CI=1 in all non-interactive environments","Pipe input explicitly when scripting (echo y | cmd)","Prefer InitPlaywright in headless services","Check TTY availability before prompting flows"],"tags":["go","stdin","interactive-prompt","eof","ci"],"backgroundTag":"stdin-read-failed","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}