{"record":{"id":"6d92a824e859e28a","repo":"cloudflare/cloudflared","slug":"error-setting-write-deadline-w","errorCode":null,"errorMessage":"error setting write deadline: %w","messagePattern":"error setting write deadline: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"websocket/connection.go","lineNumber":76,"sourceCode":"\n// Write will write messages to the websocket connection\nfunc (c *GorillaConn) Write(p []byte) (int, error) {\n\tif err := c.Conn.WriteMessage(websocket.BinaryMessage, p); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn len(p), nil\n}\n\n// SetDeadline sets both read and write deadlines, as per net.Conn interface docs:\n// \"It is equivalent to calling both SetReadDeadline and SetWriteDeadline.\"\n// Note there is no synchronization here, but the gorilla implementation isn't thread safe anyway\nfunc (c *GorillaConn) SetDeadline(t time.Time) error {\n\tif err := c.Conn.SetReadDeadline(t); err != nil {\n\t\treturn fmt.Errorf(\"error setting read deadline: %w\", err)\n\t}\n\tif err := c.Conn.SetWriteDeadline(t); err != nil {\n\t\treturn fmt.Errorf(\"error setting write deadline: %w\", err)\n\t}\n\treturn nil\n}\n\ntype Conn struct {\n\trw  io.ReadWriter\n\tlog *zerolog.Logger\n\t// writeLock makes sure\n\t// 1. Only one write at a time. The pinger and Stream function can both call write.\n\t// 2. Close only returns after in progress Write is finished, and no more Write will succeed after calling Close.\n\twriteLock sync.Mutex\n\tdone      bool\n}\n\nfunc NewConn(ctx context.Context, rw io.ReadWriter, log *zerolog.Logger) *Conn {\n\tc := &Conn{\n\t\trw:  rw,\n\t\tlog: log,","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/websocket/connection.go#L58-L94","documentation":"The write-half counterpart in GorillaConn.SetDeadline: after the read deadline is set successfully, SetWriteDeadline on the underlying gorilla connection failed. Like the read variant, this typically means the connection is closed or broken; it wraps and returns the underlying error via %w.","triggerScenarios":"SetDeadline called on a GorillaConn whose underlying connection is closed/half-broken; the read deadline succeeds but the write deadline call fails, common when the peer closed the socket between the two calls.","commonSituations":"Race between connection teardown and ping/pong keepalive loops that reset deadlines; abrupt peer disconnect mid-stream on websocket-proxied protocols (ssh/rdp over Access).","solutions":["Treat as connection-fatal: propagate the error and close/reconnect the websocket session","Stop deadline-refresh timers when Close() is called to avoid racing teardown","Filter net.ErrClosed / 'use of closed network connection' as expected during shutdown","Check the underlying TCP connection health; a write-deadline failure usually means the socket is already dead"],"exampleFix":"// before\nif err := conn.SetDeadline(t); err != nil {\n    logger.Error().Err(err).Msg(\"set deadline\")\n}\n// after — reconnect on any deadline-set failure\nif err := conn.SetDeadline(t); err != nil {\n    _ = conn.Close()\n    return reconnect(ctx)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := conn.SetDeadline(t); err != nil {\n    _ = conn.Close()\n    return fmt.Errorf(\"websocket dead, reconnect: %w\", err)\n}","preventionTips":["Treat any SetDeadline failure as connection-fatal and reconnect","Stop ping/pong keepalive loops on Close to avoid teardown races","Monitor write-deadline failures as an early signal of peer disconnects"],"tags":["websocket","deadline","write-failure","connection-lifecycle"],"backgroundTag":"connection-closed","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}