bcicen/ctop · error

Wrong frame format

Error message

Wrong frame format

What it means

docker.go's Write parses the Docker attach stream, where each frame has an 8-byte header [STREAM_TYPE,0,0,0,SIZE1..4]. If the first header byte is not one of 0/1/2 (stdin/stdout/stderr), the stream is malformed and wrongFrameFormat is returned. This guards against corrupted or non-standard multiplexed streams.

Source

Thrown at connector/manager/docker.go:38

	}
}

// Do not allow to close reader (i.e. /dev/stdin which docker client tries to close after command execution)
type noClosableReader struct {
	io.Reader
}

func (w *noClosableReader) Read(p []byte) (n int, err error) {
	return w.Reader.Read(p)
}

const (
	STDIN  = 0
	STDOUT = 1
	STDERR = 2
)

var wrongFrameFormat = errors.New("Wrong frame format")

// A frame has a Header and a Payload
// Header: [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
// STREAM_TYPE can be:
//    0: stdin (is written on stdout)
//    1: stdout
//    2: stderr
// SIZE1, SIZE2, SIZE3, SIZE4 are the four bytes of the uint32 size encoded as big endian.
// But we don't use size, because we don't need to find the end of frame.
type frameWriter struct {
	stdout io.Writer
	stderr io.Writer
	stdin  io.Writer
}

func (w *frameWriter) Write(p []byte) (n int, err error) {
	// drop initial empty frames
	if len(p) == 0 {

View on GitHub (pinned to 59f00dd6aa)

Solutions

  1. Ensure the container/connection was created with TTY disabled so Docker emits the 8-byte multiplexed frame headers
  2. Validate the first byte of each frame before parsing and skip/resync on unknown stream types
  3. Check for truncated reads — read the full 8-byte header before dispatching on STREAM_TYPE

Example fix

// before
tty: true  // raw stream, no frame headers
// after
tty: false // docker emits [STREAM_TYPE,0,0,0,SIZE...] frames that Write can parse
Defensive patterns

Strategy: validation

Validate before calling

hdr := make([]byte, 8)
if _, err := io.ReadFull(r, hdr); err != nil { return err }
if hdr[0] > 2 { return fmt.Errorf("unexpected stream type %d", hdr[0]) }

Type guard

func validStreamType(b byte) bool { return b == 0 || b == 1 || b == 2 }

Try / catch

n, err := w.Write(p)
if errors.Is(err, manager.wrongFrameFormat) || err.Error() == "Wrong frame format" {
    // resync stream or recreate connection with tty disabled
}

Prevention

When it happens

Trigger: Reading from a Docker container attach/exec stream whose first header byte is not 0, 1, or 2 (e.g. tty-mode output without the multiplexed protocol, or a truncated/corrupt header).

Common situations: Attaching to a container started with TTY enabled (raw stream, no frame headers); parsing a non-Docker or hijacked connection; reading a partial frame after a network interruption.

Related errors


AI-assisted analysis of bcicen/ctop@59f00dd6aa (2026-09-02). Data as JSON: /api/errors/8b48d846386a6493. Report an issue: GitHub.