The lifetime of Request objects is tied to the worker thread(s) in the async event loop. In the current code there's nothing that prevents a request from outliving the RpcEngine (bound to FileSystem) while it's waiting for IO. If the Request, or a task that makes a new request, outlives the RpcEngine it attempts to dereference a dangling pointer and either crashes or continues to run with bad data.
Proposed fix is to reference count the RpcEngine via shared_ptr so that Requests can hold a weak_ptr to it. When a request or RpcConnection attempting to make a request needs something from the RpcEngine like a call id number it can promote the weak_ptr to a shared_ptr. If it's unable to promote because the RpcEngine has been destroyed the Request's handler can be invoked with an appropriate error message. A weak_ptr must be used rather than a shared_ptr to avoid reference cycles.