Menu
CoddyTech

Catching Errors With try

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

A network call can fail: the phone has no signal, the server is down, the path is wrong. When fetch fails, it throws an error: an ApiException, a small class at the top of api.dart with a statusCode and a message. An error nobody catches stops your function and shows up as a red error in the Console, and the person sees a spinner that never ends.

Catch it with try and catch:

try {
  final text = await fetch('/message');
  // only runs when fetch worked
} catch (e) {
  // only runs when fetch threw
  print('It failed: $e');
}

Dart runs the try block. If anything in it throws, Dart jumps straight to catch, and e holds the error. The lines after the failing one in try never run.

Put the await itself inside try: that is the line that throws. Then show the person what happened, in words, instead of crashing.

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

Make loadMessage survive a failed call:

  • put the fetch and the setState after it in a try block
  • in catch (e), stop the spinner and set the message to Could not load: $e

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> {
  String message = 'No message yet';
  bool loading = false;

  Future<void> loadMessage() async {
    setState(() {
      loading = true;
    });
    final text = await fetch('/message');
    setState(() {
      message = text;
      loading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            loading
                ? const CircularProgressIndicator()
                : Text(message, style: const TextStyle(fontSize: 24)),
            const SizedBox(height: 24),
            ElevatedButton(onPressed: loadMessage, child: const Text('Load message')),
          ],
        ),
      ),
    );
  }
}
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