{"record":{"id":"8b48d846386a6493","repo":"bcicen/ctop","slug":"wrong-frame-format","errorCode":null,"errorMessage":"Wrong frame format","messagePattern":"Wrong frame format","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"connector/manager/docker.go","lineNumber":38,"sourceCode":"\t}\n}\n\n// Do not allow to close reader (i.e. /dev/stdin which docker client tries to close after command execution)\ntype noClosableReader struct {\n\tio.Reader\n}\n\nfunc (w *noClosableReader) Read(p []byte) (n int, err error) {\n\treturn w.Reader.Read(p)\n}\n\nconst (\n\tSTDIN  = 0\n\tSTDOUT = 1\n\tSTDERR = 2\n)\n\nvar wrongFrameFormat = errors.New(\"Wrong frame format\")\n\n// A frame has a Header and a Payload\n// Header: [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}\n// STREAM_TYPE can be:\n//    0: stdin (is written on stdout)\n//    1: stdout\n//    2: stderr\n// SIZE1, SIZE2, SIZE3, SIZE4 are the four bytes of the uint32 size encoded as big endian.\n// But we don't use size, because we don't need to find the end of frame.\ntype frameWriter struct {\n\tstdout io.Writer\n\tstderr io.Writer\n\tstdin  io.Writer\n}\n\nfunc (w *frameWriter) Write(p []byte) (n int, err error) {\n\t// drop initial empty frames\n\tif len(p) == 0 {","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/bcicen/ctop/blob/59f00dd6aaebf48f3bc501e174f75f815c2619f0/connector/manager/docker.go#L20-L56","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure the container/connection was created with TTY disabled so Docker emits the 8-byte multiplexed frame headers","Validate the first byte of each frame before parsing and skip/resync on unknown stream types","Check for truncated reads — read the full 8-byte header before dispatching on STREAM_TYPE"],"exampleFix":"// before\ntty: true  // raw stream, no frame headers\n// after\ntty: false // docker emits [STREAM_TYPE,0,0,0,SIZE...] frames that Write can parse","handlingStrategy":"validation","validationCode":"hdr := make([]byte, 8)\nif _, err := io.ReadFull(r, hdr); err != nil { return err }\nif hdr[0] > 2 { return fmt.Errorf(\"unexpected stream type %d\", hdr[0]) }","typeGuard":"func validStreamType(b byte) bool { return b == 0 || b == 1 || b == 2 }","tryCatchPattern":"n, err := w.Write(p)\nif errors.Is(err, manager.wrongFrameFormat) || err.Error() == \"Wrong frame format\" {\n    // resync stream or recreate connection with tty disabled\n}","preventionTips":["Create containers/exec with TTY disabled so frames are multiplexed","Always read the full 8-byte header before dispatching","Validate STREAM_TYPE byte before use"],"tags":["docker","stream-parsing","protocol"],"backgroundTag":"malformed-stream-frame","analyzedSha":"59f00dd6aaebf48f3bc501e174f75f815c2619f0","analyzedAt":"2026-09-02T23:34:03.832Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}