{"record":{"id":"622563cfb12ed748","repo":"microsoft/typescript-go","slug":"failed-to-write-message-w","errorCode":null,"errorMessage":"failed to write message: %w","messagePattern":"failed to write message: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/lsp/server.go","lineNumber":649,"sourceCode":"\nfunc (s *Server) writeLoop(ctx context.Context) error {\n\tfor {\n\t\tmsg, err := s.outgoingQueue.Get(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := s.w.Write(msg); err != nil {\n\t\t\tvar marshalErr *messageMarshalError\n\t\t\tif errors.As(err, &marshalErr) && msg.Kind == jsonrpc.MessageKindResponse {\n\t\t\t\tif resp := msg.AsResponse(); resp.ID != nil && resp.Error == nil {\n\t\t\t\t\ts.logger.Errorf(\"failed to marshal response for request %s: %v\", resp.ID, marshalErr)\n\t\t\t\t\tif sendErr := s.sendError(resp.ID, marshalErr); sendErr != nil {\n\t\t\t\t\t\treturn sendErr\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to write message: %w\", err)\n\t\t}\n\t}\n}\n\n// WARNING: this should only be called in the async portion of a request handler,\n// otherwise a deadlock can occur.\nfunc sendClientRequest[Req, Resp any](ctx context.Context, s *Server, info lsproto.RequestInfo[Req, Resp], params Req) (Resp, error) {\n\tid := jsonrpc.NewIDString(fmt.Sprintf(\"ts%d\", s.clientSeq.Add(1)))\n\treq := info.NewRequestMessage(id, params)\n\n\tresponseChan := make(chan *lsproto.ResponseMessage, 1)\n\ts.pendingServerRequestsMu.Lock()\n\ts.pendingServerRequests[*id] = responseChan\n\ts.pendingServerRequestsMu.Unlock()\n\n\tdefer func() {\n\t\ts.pendingServerRequestsMu.Lock()\n\t\tdefer s.pendingServerRequestsMu.Unlock()","sourceCodeStart":631,"sourceCodeEnd":667,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/lsp/server.go#L631-L667","documentation":"Raised in the server's outbound write loop when s.w.Write(msg) fails while pushing a JSON-RPC message to the client transport. It means the underlying writer (stdio pipe or client connection) is broken, so no further messages can be delivered and the write loop terminates. A special case exists for messageMarshalError on responses: the server attempts to substitute an error response instead of failing, but every other write error (broken pipe, closed conn, marshal error on a request/notification) propagates as this wrapped error.","triggerScenarios":"Client process crashes or closes stdin/stdout while the server is mid-response; LSP client cancels and tears down the connection during a large hover/completion payload; a response contains types the marshaler cannot serialize and msg is not a response with a settable Error field; malformed lsproto struct handed to Write from a custom handler.","commonSituations":"Editor window closed during a long-running diagnostics pass; wrapper (node/npm shim) between editor and server dying; pipe buffer backpressure combined with client exit; version mismatch where a newly added response field is a non-marshalable Go type.","solutions":["Check whether the client is still alive when this fires; if the editor exited, this error is expected shutdown noise, not a bug","If it is a marshal failure, reproduce with logging: the code already logs 'failed to marshal response for request %s' before retrying with sendError; capture that log to identify the offending field","Ensure custom handler return values only contain lsproto-generated, JSON-tagged structs","If the transport closes by design, drain/ignore the error after shutdown is initiated instead of treating it as fatal"],"exampleFix":"// before\nif err := s.w.Write(msg); err != nil {\n\treturn fmt.Errorf(\"failed to write message: %w\", err)\n}\n\n// after (ignore write failures once shutdown has begun)\nif err := s.w.Write(msg); err != nil {\n\tif s.isShutdown() {\n\t\ts.logger.Warn(\"write after shutdown:\", err)\n\t\tcontinue\n\t}\n\treturn fmt.Errorf(\"failed to write message: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := s.w.Write(msg); err != nil {\n\tvar marshalErr *messageMarshalError\n\tif errors.As(err, &marshalErr) && canSynthesizeErrorFor(msg) {\n\t\t// route through sendError replacement, keep loop alive\n\t\tcontinue\n\t}\n\tif s.shutdownStarted() {\n\t\treturn nil // client went away during shutdown - not a defect\n\t}\n\treturn fmt.Errorf(\"failed to write message: %w\", err)\n}","preventionTips":["Treat any error containing 'failed to write message' after client exit as expected shutdown noise","Keep handler response types limited to lsproto-generated structs to avoid marshal errors","Add a shutdown flag checked in the write loop before returning the error"],"tags":["jsonrpc","transport","io","shutdown"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}