gorilla/websocket · error

websocket: bad write message type

Error message

websocket: bad write message type

What it means

errBadWriteOpCode is returned when WriteMessage is called with an invalid message type — anything other than TextMessage (1), BinaryMessage (2), or an allowed control opcode the write path accepts. The library validates the messageType before writing.

Source

Thrown at conn.go:178

// IsUnexpectedCloseError returns boolean indicating whether the error is a
// *CloseError with a code not in the list of expected codes.
func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
	if e, ok := err.(*CloseError); ok {
		for _, code := range expectedCodes {
			if e.Code == code {
				return false
			}
		}
		return true
	}
	return false
}

var (
	errWriteTimeout        = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
	errUnexpectedEOF       = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
	errBadWriteOpCode      = errors.New("websocket: bad write message type")
	errWriteClosed         = errors.New("websocket: write closed")
	errInvalidControlFrame = errors.New("websocket: invalid control frame")
)

// maskRand is an io.Reader for generating mask bytes. The reader is initialized
// to crypto/rand Reader. Tests swap the reader to a math/rand reader for
// reproducible results.
var maskRand = rand.Reader

// newMaskKey returns a new 32 bit value for masking client frames.
func newMaskKey() [4]byte {
	var k [4]byte
	_, _ = io.ReadFull(maskRand, k[:])
	return k
}

func isControl(frameType int) bool {
	return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage

View on GitHub (pinned to e064f32e36)

Solutions

  1. Pass only websocket.TextMessage or websocket.BinaryMessage as the first argument to WriteMessage
  2. Check for swapped arguments if using a variable message type
  3. Validate any externally-configured message type against the two allowed constants

Example fix

// before
if err := conn.WriteMessage(msgType, payload); err != nil { ... } // msgType is 0
// after
if msgType != websocket.TextMessage && msgType != websocket.BinaryMessage {
    msgType = websocket.TextMessage
}
if err := conn.WriteMessage(msgType, payload); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

func validMessageType(t int) bool {
    return t == websocket.TextMessage || t == websocket.BinaryMessage
}

Type guard

func isTextOrBinary(t int) bool {
    return t == websocket.TextMessage || t == websocket.BinaryMessage
}

Try / catch

if !validMessageType(msgType) {
    return fmt.Errorf("invalid message type %d", msgType)
}
if err := conn.WriteMessage(msgType, payload); err != nil {
    return err
}

Prevention

When it happens

Trigger: Calling conn.WriteMessage with a messageType constant that is not websocket.TextMessage or websocket.BinaryMessage (e.g. 0, 3-10, or an uninitialized variable), including accidentally passing the message payload's first byte as the type.

Common situations: Passing a dynamic/int messageType computed elsewhere, off-by-one or swapped arguments like WriteMessage(data, websocket.TextMessage), or reusing opcode constants from another WebSocket library.

Related errors


AI-assisted analysis of gorilla/websocket@e064f32e36 (2026-08-31). Data as JSON: /api/errors/b434aaddb6824c27. Report an issue: GitHub.