wavetermdev/waveterm · error

error writing trailing newline to output (AdaptOutputChToStr

Error message

error writing trailing newline to output (AdaptOutputChToStream): %w

What it means

AdaptOutputChToStream writes a trailing newline after every message to frame them on the output stream. This error wraps a failure when writing that newline byte, meaning the underlying writer broke mid-message-stream even if the message body itself was written.

Source

Thrown at pkg/wshutil/wshrpcio.go:40

	}, readCallback)
}

func AdaptOutputChToStream(outputCh chan []byte, output io.Writer) error {
	drain := false
	defer func() {
		if drain {
			utilfn.DrainChannelSafe(outputCh, "AdaptOutputChToStream")
		}
	}()
	for msg := range outputCh {
		if _, err := output.Write(msg); err != nil {
			drain = true
			return fmt.Errorf("error writing to output (AdaptOutputChToStream): %w", err)
		}
		// write trailing newline
		if _, err := output.Write([]byte{'\n'}); err != nil {
			drain = true
			return fmt.Errorf("error writing trailing newline to output (AdaptOutputChToStream): %w", err)
		}
	}
	return nil
}

func AdaptMsgChToPty(outputCh chan []byte, oscEsc string, output io.Writer) error {
	if len(oscEsc) != 5 {
		panic("oscEsc must be 5 characters")
	}
	for msg := range outputCh {
		barr, err := EncodeWaveOSCBytes(oscEsc, msg)
		if err != nil {
			return fmt.Errorf("error encoding osc message (AdaptMsgChToPty): %w", err)
		}
		if _, err := output.Write(barr); err != nil {
			return fmt.Errorf("error writing osc message (AdaptMsgChToPty): %w", err)
		}
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped error for the underlying write failure (EPIPE, ENOSPC).
  2. Keep the output stream open for the lifetime of the channel pump.
  3. Check available disk space if output is redirected to a file.
  4. Treat as a broken consumer and shut down the producer gracefully.
Defensive patterns

Strategy: try-catch

Validate before calling

if f, ok := output.(*os.File); ok {
    if _, err := f.Stat(); err != nil {
        return fmt.Errorf("output closed: %w", err)
    }
}

Type guard

func isClosedFile(w io.Writer) bool {
    f, ok := w.(*os.File)
    if !ok { return false }
    _, err := f.Stat()
    return err != nil
}

Try / catch

err := AdaptOutputChToStream(ch, output)
if err != nil {
    if errors.Is(err, syscall.EPIPE) { return nil }
    return fmt.Errorf("stream write failed: %w", err)
}

Prevention

When it happens

Trigger: The io.Writer returned an error specifically on the `output.Write([]byte{'\n'})` call after a successful message write — typically a pipe that just closed or filled between the two writes.

Common situations: Output stream closes between message body and newline writes; disk-full when output is a file; a pty or pipe that errored after partial write.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/98bd99952d5355b5. Report an issue: GitHub.