netbirdio/netbird · warning

failed handling request

Error message

failed handling request

What it means

WriteErrorResponse has already written the HTTP status and Content-Type when json.Encode of the ErrorResponse body fails. The fallback http.Error cannot change the status line anymore, so the client receives the intended status with a truncated or empty body. The usual cause is the client disconnecting while the error response was being written, not a server fault. The original handler error was already logged by WriteError before this point.

Source

Thrown at shared/management/http/util/util.go:78

		if err != nil {
			return err
		}
		return nil
	default:
		return errors.New("invalid duration")
	}
}

// WriteErrorResponse prepares and writes an error response i nJSON
func WriteErrorResponse(errMsg string, httpStatus int, w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(httpStatus)
	err := json.NewEncoder(w).Encode(&ErrorResponse{
		Message: errMsg,
		Code:    httpStatus,
	})
	if err != nil {
		http.Error(w, "failed handling request", http.StatusInternalServerError)
	}
}

// WriteError converts an error to an JSON error response.
// If it is known internal error of type server.Error then it sets the messages from the error, a generic message otherwise
func WriteError(ctx context.Context, err error, w http.ResponseWriter) {
	log.WithContext(ctx).Errorf("got a handler error: %s", err.Error())
	errStatus, ok := status.FromError(err)
	httpStatus := http.StatusInternalServerError
	msg := "internal server error"
	if ok {
		switch errStatus.Type() {
		case status.UserAlreadyExists:
			httpStatus = http.StatusConflict
		case status.AlreadyExists:
			httpStatus = http.StatusConflict
		case status.PreconditionFailed:
			httpStatus = http.StatusPreconditionFailed

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Match against the server logs: the real handler error was logged by WriteError before this fallback fired
  2. Raise or remove short client timeouts for management API calls
  3. Retry the request if it is idempotent; the disconnect does not imply the operation failed
  4. If it reproduces on a stable connection, investigate response size or proxying in between
Defensive patterns

Strategy: retry

Try / catch

resp, err := doManagementCall(req)
if err == nil && resp.StatusCode >= 500 {
    body, rerr := io.ReadAll(resp.Body)
    if rerr != nil || len(body) == 0 {
        // the error response itself failed to encode (client disconnect);
        // the server already logged the real cause. Retry idempotent calls with backoff.
    }
}

Prevention

When it happens

Trigger: A management REST handler returns an error and the client aborts the connection (timeout, cancel, navigation) before the JSON error body is fully encoded.

Common situations: Aggressive client-side timeouts in CLI or API scripts; browsers cancelling in-flight requests; load balancers cutting slow responses.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/cbf6f59d4a3bcd71. Report an issue: GitHub.