microsoft/typescript-go · error

api: failed to write server timing response: %v

Error message

api: failed to write server timing response: %v

What it means

While handling the $/getServerTiming meta-request, SyncConn failed to write the response and panics with the write error. The transport itself is broken (closed pipe/conn), so the server deliberately crashes rather than silently drop the timing reply.

Source

Thrown at internal/api/conn_sync.go:93

			c.handleNotification(ctx, msg)
		} else {
			// Responses are not expected in the main loop - they are read inline by Call().
			return errors.New("api: unexpected response message in sync connection")
		}
	}
}

// handleRequest processes an incoming request.
func (c *SyncConn) handleRequest(ctx context.Context, msg *Message) {
	// Intercept the meta-requests for collected server timing before dispatching
	// to the handler, so they are answered directly and not themselves recorded.
	switch msg.Method {
	case string(MethodGetServerTiming):
		c.mu.Lock()
		writeErr := c.protocol.WriteResponse(msg.ID, serverTimingSnapshot(c.timing))
		c.mu.Unlock()
		if writeErr != nil {
			panic(fmt.Sprintf("api: failed to write server timing response: %v", writeErr))
		}
		return
	case string(MethodResetServerTiming):
		if c.timing != nil {
			c.timing.reset()
		}
		c.mu.Lock()
		writeErr := c.protocol.WriteResponse(msg.ID, nil)
		c.mu.Unlock()
		if writeErr != nil {
			panic(fmt.Sprintf("api: failed to write reset server timing response: %v", writeErr))
		}
		return
	}

	var result any
	var err error

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Ensure clients wait for outstanding meta-request responses before closing the connection
  2. Gracefully shut down: stop the read loop before closing the transport
  3. If it recurs in production, capture the write error (broken pipe vs reset) to find who closes first
  4. Treat as a shutdown-race symptom: reproduce with connection-close timing under debug
Defensive patterns

Strategy: try-catch

Try / catch

// client side: keep the connection open until all meta-request responses arrive
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
_, err := conn.Call(ctx, "getServerTiming", nil)
if err != nil { /* transport closed mid-reply: retry on a fresh connection */ }

Prevention

When it happens

Trigger: Client closed the connection (or crashed) between sending getServerTiming and the server's response write; I/O error on the underlying transport; shutdown racing an in-flight meta-request.

Common situations: Editor/LSP client timing out and closing the connection right as it polls server timings; tests tearing down connections without draining pending requests.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/6022dc60c2766ecf. Report an issue: GitHub.