{"record":{"id":"dde1f6e6d67858c1","repo":"microsoft/typescript-go","slug":"api-failed-to-write-panic-error-response-v-ori","errorCode":null,"errorMessage":"api: failed to write panic error response: %v (original panic: %v)","messagePattern":"api: failed to write panic error response: (.+?) \\(original panic: (.+?)\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/api/conn_sync.go","lineNumber":131,"sourceCode":"\tif c.timing != nil {\n\t\tstart = time.Now()\n\t}\n\n\t// Recover from panics and convert to error response with stack trace\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tstack := string(debug.Stack())\n\t\t\terr = fmt.Errorf(\"panic: %v\\n%s\", r, stack)\n\n\t\t\tc.mu.Lock()\n\t\t\twriteErr := c.protocol.WriteError(msg.ID, &jsonrpc.ResponseError{\n\t\t\t\tCode:    jsonrpc.CodeInternalError,\n\t\t\t\tMessage: err.Error(),\n\t\t\t})\n\t\t\tc.mu.Unlock()\n\n\t\t\tif writeErr != nil {\n\t\t\t\tpanic(fmt.Sprintf(\"api: failed to write panic error response: %v (original panic: %v)\", writeErr, r))\n\t\t\t}\n\t\t}\n\t}()\n\n\tresult, err = c.handler.HandleRequest(ctx, msg.Method, msg.Params)\n\n\tif c.timing != nil {\n\t\tc.timing.record(msg.Method, time.Since(start))\n\t}\n\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tvar writeErr error\n\tif err != nil {\n\t\twriteErr = c.protocol.WriteError(msg.ID, &jsonrpc.ResponseError{\n\t\t\tCode:    jsonrpc.CodeInternalError,\n\t\t\tMessage: err.Error(),","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/conn_sync.go#L113-L149","documentation":"Raised inside the deferred recover of SyncConn.handleRequest when a request handler panicked AND the follow-up attempt to write the JSON-RPC error response to the client also failed. The connection is already unusable, so the code re-panics with both the write error and the original panic value, tearing down the connection's Run loop.","triggerScenarios":"c.handler.HandleRequest panics (nil dereference, index out of range in project/ast code) while the peer has already closed the transport or the pipe is broken, so protocol.WriteError under c.mu returns EPIPE/EOF/use-of-closed-connection.","commonSituations":"Editor or LSP-style client disconnects (restart, crash, cancelled request) at the exact moment the server hits a bug; test harnesses closing the io.ReadWriteCloser before the last response is flushed; half-closed TCP connections in CI.","solutions":["Treat the ORIGINAL panic (second %v in the message) as the root cause and chase its stack, not the write failure","Fix or guard the panic inside the request handler","Keep the peer's connection open until the final response for every request it sent has been written, or drain gracefully on shutdown","If you embed SyncConn, wrap Run with a recover so this becomes a logged connection teardown instead of a process crash"],"exampleFix":"// before\nfunc main() { conn.Run(ctx) } // panic kills the process\n\n// after\nfunc main() {\n\tdefer func() { if r := recover(); r != nil { log.Printf(\"conn crashed: %v\", r) } }()\n\tconn.Run(ctx)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Wrap the connection loop; a panic here always means the connection is dead.\nfunc serve(conn *api.SyncConn, ctx context.Context) error {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlog.Printf(\"connection terminated by panic: %v\", r)\n\t\t}\n\t}()\n\treturn conn.Run(ctx)\n}","preventionTips":["Keep the transport open until every in-flight request has been answered","Wrap SyncConn.Run in a recover so a broken pipe plus handler panic logs instead of killing the process","Fix handler panics reported in the embedded stack before chasing the write failure"],"tags":["go","panic","connection","broken-pipe","jsonrpc","sync-conn"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}