restic/restic · warning
write failed: %w
Error message
write failed: %w
What it means
PosixClearCurrentLine failed to write its ANSI escape sequence (cursor-home + clear-line) to the progress-display writer. This is status-line cosmetics for interactive terminals; the wrapped error is virtually always EPIPE (reader gone) or ENOSPC/EIO when output is redirected.
Source
Thrown at internal/terminal/terminal_posix.go:26
const (
// PosixControlMoveCursorHome moves cursor to the first column
PosixControlMoveCursorHome = "\r"
// PosixControlMoveCursorUp moves cursor up one line
PosixControlMoveCursorUp = "\x1b[1A"
// PosixControlMoveCursorDown moves cursor down one line
PosixControlMoveCursorDown = "\x1b[1B"
// PosixControlClearLine clears the current line
PosixControlClearLine = "\x1b[2K"
)
// PosixClearCurrentLine removes all characters from the current line and resets the
// cursor position to the first column.
func PosixClearCurrentLine(wr io.Writer, _ uintptr) error {
// clear current line
_, err := wr.Write([]byte(PosixControlMoveCursorHome + PosixControlClearLine))
if err != nil {
return fmt.Errorf("write failed: %w", err)
}
return nil
}
// PosixMoveCursorUp moves the cursor to the line n lines above the current one.
func PosixMoveCursorUp(wr io.Writer, _ uintptr, n int) error {
data := []byte(PosixControlMoveCursorHome)
data = append(data, bytes.Repeat([]byte(PosixControlMoveCursorUp), n)...)
_, err := wr.Write(data)
if err != nil {
return fmt.Errorf("write failed: %w", err)
}
return nil
}
// PosixMoveCursorDown moves the cursor to the line n lines below the current one.
func PosixMoveCursorDown(wr io.Writer, _ uintptr, n int) error {
data := []byte(PosixControlMoveCursorHome)View on GitHub (pinned to a80be1478a)
Solutions
- Keep the downstream reader alive for the whole run, or redirect to a file instead of a pipe
- Free disk space when redirecting to a full filesystem
- Use --json (or quiet mode) in scripts to disable in-place status rendering entirely
- Treat it as non-fatal if your own tooling consumed enough output — the backup itself usually continues
Example fix
# before restic backup /data | head -5 # Error: write failed: broken pipe # after (file redirect or quiet mode in scripts) restic backup /data --quiet >> /var/log/restic.log 2>&1
Defensive patterns
Strategy: try-catch
Validate before calling
// only render interactive status when the writer is a real terminal
if term.IsTerminal(int(os.Stdout.Fd())) {
_ = terminal.PosixClearCurrentLine(os.Stdout, fd)
} Try / catch
if err := terminal.PosixClearCurrentLine(w, fd); err != nil {
if errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ENOSPC) {
return // cosmetic: drop progress rendering, keep the operation running
}
return err
} Prevention
- Use --quiet or --json for any scripted/piped invocation
- Redirect logs to files, not to early-exiting pipes like head
- Register signal handling to ignore SIGPIPE for status writes
When it happens
Trigger: restic's stdout is piped into a program that exits early (head, grep -m1) so writes hit a closed pipe; output redirected to a file on a full disk; terminal window closed while a long operation renders progress.
Common situations: Piping restic through head in scripts; killing the pager but not restic; /tmp or log volume full when redirecting; CI capturing output with small buffers that close early.
Related errors
- ReadPassword: %w
- unknown message type
- unknown message type
- blob is larger than 4GB
- overlapping blobs in pack %v
AI-assisted analysis of restic/restic@a80be1478a (2026-08-15).
Data as JSON: /api/errors/d15303113fdb15b8.
Report an issue: GitHub.