title: Catching a synchronous error in an async function called by FutureBuilder
body: <p>I have a FutureBuilder widget which calls an async function that is meant to fetch a list of controls available for a given device from a remote server.</p>
  <pre><code>FutureBuilder&lt;List&lt;Control&gt;&gt; buildControlList() {
      return FutureBuilder&lt;List&lt;Control&gt;&gt;(
          future: widget.server.getResponse(widget.device, widget.controlSet),
          builder:
              (BuildContext context, AsyncSnapshot&lt;List&lt;Control&gt;&gt; snapshot) {
            if (snapshot.hasData) {
              return buildList(buildControls(widget.controlSet, snapshot.data));
            } else if (snapshot.hasError) {
              Scaffold.of(context).showSnackBar(
                  SnackBar(content: Text('${snapshot.error.toString()}')));
            }
            return const Center(child: CircularProgressIndicator());
          });
  }
  </code></pre>
  <p>The getResponse function calls another async _get function which builds and performs the actual api request. Once a response is received, it send the response data to a synchronous function which checks the content for errors reported by the server. If it finds one, it throws its own error:</p>
  <pre><code>Future&lt;List&lt;Control&gt;&gt; getResponse(Device device, ControlSet controlSet,
    {Map&lt;String, dynamic&gt; params}) async {
      final String epoint = 'device/${device.name}/set/${controlSet.name}/';
      final http.Response response = await _get(epoint, params: params);
      _checkServerError(response); //synchronous check of response data
      final List&lt;Control&gt; values =
          json.decode(response.body).map&lt;Control&gt;((dynamic e) {
        return Control.fromJson(e);
      }).toList();
      return values;
  }
  </code></pre>
  <p>The _checkServerError function is pretty simple. I have tried both sync and async versions of this and seem to have the same behavior.</p>
  <pre><code>void _checkServerError(http.Response response) {
      if (response.statusCode != 200) {
        final Map&lt;String, dynamic&gt; body = json.decode(response.body);
        if (body.containsKey('error')) {
          throw ServerException(
              statusCode: response.statusCode, errorMsg: body['error']);
        }
      }
  }
  </code></pre>
  <p>I cannot seem to get the thrown ServerException to propagate up to the FutureBuilder's snapshot.hasError check. I don't want to have to catch the error and re-throw it in the getResponse() function though it does appear to work. Changing _checkServerError() to an async function and awaiting it does not seem to work either.</p>
  <p>Why doesn't the error continue upwards to the FutureBuilder?</p>
  <p>Edit: The call stack shows the error originating in _checkServerError() and propagating upwards to the FutureBuilder inside buildControlList(). So it is getting there. However, the FutureBuilder doesn't appear to be catching it and interpreting it as an errored &quot;snapshot&quot;. Perhaps I'm not using the FutureBuilder correctly? There is also this  from an &quot;Unknown Source&quot;. Not sure how to interpret that.</p>
  <p>Call stack:</p>
  <pre><code>Server._checkServerError (/mobile-client/lib/services/server.dart:75)
  Server.getResponse (/mobile-client/lib/services/server.dart:112)
  &lt;asynchronous gap&gt; (Unknown Source:0)
  _ControlsScreen.buildControlList (/mobile-client/lib/screens/devices/controls.dart:71)
  _ControlsScreen.build.&lt;anonymous closure&gt; (/mobile-client/lib/screens/devices/controls.dart:50)
  Consumer.buildWithChild (/provider-4.0.5+1/lib/src/consumer.dart:175)
  SingleChildStatelessWidget.build (/nested-0.0.4/lib/nested.dart:260)
  StatelessElement.build (/lib/src/widgets/framework.dart:4576)
  SingleChildStatelessElement.build (/nested-0.0.4/lib/nested.dart:280)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4502)
  Element.rebuild (/lib/src/widgets/framework.dart:4218)
  StatelessElement.update (/lib/src/widgets/framework.dart:4583)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4527)
  Element.rebuild (/lib/src/widgets/framework.dart:4218)
  StatelessElement.update (/lib/src/widgets/framework.dart:4583)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4527)
  Element.rebuild (/lib/src/widgets/framework.dart:4218)
  ProxyElement.update (/lib/src/widgets/framework.dart:4862)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4527)
  Element.rebuild (/lib/src/widgets/framework.dart:4218)
  ProxyElement.update (/lib/src/widgets/framework.dart:4862)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  RenderObjectElement.updateChildren (/lib/src/widgets/framework.dart:5522)
  MultiChildRenderObjectElement.update (/lib/src/widgets/framework.dart:5957)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4527)
  StatefulElement.performRebuild (/lib/src/widgets/framework.dart:4675)
  Element.rebuild (/lib/src/widgets/framework.dart:4218)
  StatefulElement.update (/lib/src/widgets/framework.dart:4707)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4527)
  Element.rebuild (/lib/src/widgets/framework.dart:4218)
  ProxyElement.update (/lib/src/widgets/framework.dart:4862)
  Element.updateChild (/lib/src/widgets/framework.dart:3201)
  ComponentElement.performRebuild (/lib/src/widgets/framework.dart:4527)
  StatefulElement.performRebuild (/lib/src/widgets/framework.dart:4675)
  </code></pre>