{"record":{"id":"319f015f1407daab","repo":"gorilla/websocket","slug":"websocket-close-sent","errorCode":null,"errorMessage":"websocket: close sent","messagePattern":"websocket: close sent","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"conn.go","lineNumber":86,"sourceCode":"\tBinaryMessage = 2\n\n\t// CloseMessage denotes a close control message. The optional message\n\t// payload contains a numeric code and text. Use the FormatCloseMessage\n\t// function to format a close message payload.\n\tCloseMessage = 8\n\n\t// PingMessage denotes a ping control message. The optional message payload\n\t// is UTF-8 encoded text.\n\tPingMessage = 9\n\n\t// PongMessage denotes a pong control message. The optional message payload\n\t// is UTF-8 encoded text.\n\tPongMessage = 10\n)\n\n// ErrCloseSent is returned when the application writes a message to the\n// connection after sending a close message.\nvar ErrCloseSent = errors.New(\"websocket: close sent\")\n\n// ErrReadLimit is returned when reading a message that is larger than the\n// read limit set for the connection.\nvar ErrReadLimit = errors.New(\"websocket: read limit exceeded\")\n\n// netError satisfies the net Error interface.\ntype netError struct {\n\tmsg       string\n\ttemporary bool\n\ttimeout   bool\n}\n\nfunc (e *netError) Error() string   { return e.msg }\nfunc (e *netError) Temporary() bool { return e.temporary }\nfunc (e *netError) Timeout() bool   { return e.timeout }\n\n// CloseError represents a close message.\ntype CloseError struct {","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/gorilla/websocket/blob/e064f32e3674d9d79a8fd417b5bc06fa5c6cad8f/conn.go#L68-L104","documentation":"ErrCloseSent is returned when the application attempts to write a data message after a close message has already been sent on the connection. The library tracks close-handshake state; once the client sends Close, further message writes are invalid per RFC 6455.","triggerScenarios":"Calling WriteMessage/WritePreparedMessage (or NextWriter-based writes) after calling CloseMessage or a Close with a code/reason; also triggered by the library internally after close frames. Control frames Pong/Ping may still be permitted per spec nuances.","commonSituations":"Concurrent goroutines where one sends a close while another is still writing messages; application teardown order closing the connection before flushing pending writes; read pump error handlers sending close then the write pump continuing.","solutions":["Treat ErrCloseSent as a normal shutdown signal — stop writing and return without treating it as fatal","Coordinate goroutines with context cancellation or a done channel so no writes occur after CloseMessage","Use a mutex or single-writer goroutine pattern to serialize all writes","Check conn.WriteMessage errors with errors.Is(err, websocket.ErrCloseSent) to branch shutdown logic"],"exampleFix":"// before\nif err := conn.WriteMessage(websocket.TextMessage, data); err != nil {\n    log.Fatal(err)\n}\n// after\nif err := conn.WriteMessage(websocket.TextMessage, data); err != nil {\n    if errors.Is(err, websocket.ErrCloseSent) {\n        return nil // normal during shutdown\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isCloseSent(err error) bool {\n    return errors.Is(err, websocket.ErrCloseSent)\n}","tryCatchPattern":"if err := conn.WriteMessage(websocket.TextMessage, data); err != nil {\n    if errors.Is(err, websocket.ErrCloseSent) {\n        return nil // shutdown in progress; not a failure\n    }\n    return err\n}","preventionTips":["Centralize all writes in one goroutine; close the channel to signal shutdown","Cancel writers via context before calling CloseMessage","Never write after the read pump reports a closure error"],"tags":["websocket","close-handshake","concurrency"],"backgroundTag":"websocket-close-sent","analyzedSha":"e064f32e3674d9d79a8fd417b5bc06fa5c6cad8f","analyzedAt":"2026-08-31T12:40:58.222Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}