Menu
CoddyTech

The FutureBuilder Error State

Part of the Data and the Network section of Coddy's Flutter journey. Lesson 13 of 27.

A FutureBuilder catches errors for you. When its future throws, nothing crashes: the builder runs again with snapshot.hasError set to true, and snapshot.error holds what was thrown.

That gives every loading screen three states, and the builder handles each one:

if (snapshot.hasError) {
  return Text('Could not load: ${snapshot.error}');
}
if (snapshot.hasData) {
  return Text(snapshot.data!);
}
return const CircularProgressIndicator();

Error, data, and otherwise still loading. A builder that only knows about data shows the spinner forever when the call fails, because there is never any data.

Put each check before the return that would hide it. If the spinner's return comes first for "no data", the error line below it can never run.

To see it fail in the preview, write offline = true; as the first line of main and press Run. offline comes from api.dart: it makes every call fail as if the phone had no signal. Take the line out before you press Check.

challenge icon

Challenge

Medium

With no connection, this screen spins forever. Give the builder its error state: when snapshot.hasError, show Could not load: followed by snapshot.error, size 20.

Try it yourself

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MessageScreen(),
    );
  }
}

class MessageScreen extends StatefulWidget {
  const MessageScreen({super.key});

  @override
  State<MessageScreen> createState() => _MessageScreenState();
}

class _MessageScreenState extends State<MessageScreen> {
  late Future<String> _message;

  @override
  void initState() {
    super.initState();
    _message = fetch('/message');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FutureBuilder<String>(
          future: _message,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Text(snapshot.data!, style: const TextStyle(fontSize: 24));
            }
            return const CircularProgressIndicator();
          },
        ),
      ),
    );
  }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Data and the Network

Practice on your own: Online Flutter compiler