Skip to chapter content

Chapter 3 3 min read

Never Trust the Network — Error Handling

WP_Error convention, the habit to build now

If you tried the last exercise in Chapter 2, disconnecting your AI provider and reloading the page, you already saw the problem. The whole page broke. Not a nice error message, not a fallback, the entire page failed because one function assumed an API call would always succeed.

That assumption doesn’t hold. An AI call is a request over the network to a service you don’t control. Rate limits, expired API keys, a provider having a bad day, any of these can make generate_text() fail, and none of them are things your code can prevent. What it can do is fail without taking the whole page down with it.

WP_Error, not an exception

If you’ve used wp_remote_get() before, you already know the pattern the AI Client follows. Instead of throwing an exception when something goes wrong, a failed call returns a WP_Error object in place of whatever you were expecting. Nothing crashes. But if your code doesn’t check for it, you end up calling methods on an object that isn’t the string you assumed it was, which is exactly what happened when you disconnected the provider a minute ago.

The fix is one if block, checked with is_wp_error():

$result = wp_ai_client_prompt( 'Write a haiku about WordPress.' )
->generate_text();
if ( is_wp_error( $result ) ) {
return 'Could not generate a haiku right now: ' . esc_html( $result->get_error_message() );
}
return wp_kses_post( $result );

get_error_message() gives you a human-readable string describing what went wrong, straight from the provider or from WordPress itself. Good enough to show a site owner, though probably not something you’d want a site visitor staring at on a public page (a plain “This feature is temporarily unavailable” reads better to a stranger than an API error string).

Fixing Chapter 2 for real

This is the fix Chapter 2 promised. Open includes/chapter-02-your-first-ai-call.php and update ai_course_ch2_first_call() to match the version above. Here’s the full file after the change:

<?php
/**
* Chapter 2: Your First AI Call
* Usage: add [ai_course_ch2] to any page or post to see the output.
*
* Updated in Chapter 3 to check for a WP_Error before using the result,
* instead of assuming generate_text() always succeeds.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access.
}
function ai_course_ch2_first_call() {
$result = wp_ai_client_prompt( 'Write a haiku about WordPress.' )
->generate_text();
if ( is_wp_error( $result ) ) {
return 'Could not generate a haiku right now: ' . esc_html( $result->get_error_message() );
}
return wp_kses_post( $result );
}
add_shortcode( 'ai_course_ch2', 'ai_course_ch2_first_call' );

Save it, disconnect your provider again the same way you did at the end of Chapter 2, and reload the page with [ai_course_ch2] on it. This time you get a message instead of a broken page. Reconnect the provider afterward so the rest of this chapter’s examples work.

This pattern repeats for the rest of the series

Every function we write from here forward starts the same way: call a generation method, check is_wp_error() before touching the result, only then do something with it. It stops being interesting after the second or third time you see it, which is exactly the point, it’s meant to become automatic, not something you have to think about for every new example.

There’s more to say about failure handling than a single if block, what the error actually contains, how to log it, how to tell a rate limit apart from a missing provider, but that’s further along in the series (Chapter 16 covers the full result object, including everything a successful call gives you beyond just the text). For now, this is the check that matters: never hand an unchecked result to the rest of your code.

Try it yourself

Go back to the prompt you wrote for yourself in Chapter 2’s exercise. Add the same is_wp_error() check to it if you haven’t already, then break it on purpose again, disconnect the provider, or, if you’re using a free-tier key, send enough requests in a row to hit a rate limit. Confirm you get your own error message instead of a crash. Then put the provider back and move on to Chapter 4, where we stop treating every prompt the same way and start telling the AI what role it’s supposed to be playing.

This book is created with Chapterwright