Chapter 4
Debugging AI Client Failures
is_wp_error() tells you that something failed; this is how you find out why
Chapter 3 taught you to check is_wp_error() and show a friendly message. That’s the right move for anything a site visitor might see. But a friendly message was never meant to tell you enough to actually fix something while you’re building. You need to see more than that, and this chapter is about how, in a way you can reuse for the rest of the book, not just this one chapter.
get_error_message() isn’t the whole error
A WP_Error object can carry more than the string get_error_message() hands you. There’s also get_error_code(), a short identifier for what kind of failure this was, and get_error_data(), which can hold extra context: raw response details, provider-specific fields, whatever the AI Client attached when it built the error. get_error_message() is the summary. The other two are where the actual diagnostic detail tends to live.
Building a helper worth keeping
Rather than writing a one-off debug block every time something looks wrong, this chapter builds a small function once and reuses it from here on. Create 00-helpers.php inside includes (note the naming, this isn’t a chapter file, it’s a book-wide helper, which is also why it’s named differently from every other file in this folder):
<?php
/**
* Book-wide helper functions, not tied to any single chapter.
* Loaded automatically by the bootstrap's glob() loop, same as every
* chapter file in this folder.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access.
}
/**
* Formats a generate_*() result (success or WP_Error) as readable text,
* for debugging during development. Introduced in Chapter 4, reused in
* later chapters whenever a result needs a closer look than a friendly
* error message can give.
*
* @param mixed $result Whatever a generate_*() method returned.
* @return string Readable debug output.
*/
function ai_course_debug_dump( $result ) {
if ( is_wp_error( $result ) ) {
$debug = 'Error code: ' . $result->get_error_code() . "\n";
$debug .= 'Error message: ' . $result->get_error_message() . "\n";
$debug .= 'Error data: ' . print_r( $result->get_error_data(), true );
} else {
$debug = "Success. Raw value:\n" . print_r( $result, true );
}
return $debug;
}
ai_course_debug_dump() takes whatever a generate_*() method handed back, error or success, and turns it into readable text. Nothing about it is specific to any one prompt or any one chapter. From here forward, whenever a result isn’t doing what you expect, this is the first thing to reach for: ai_course_debug_dump( $result ), instead of rebuilding this same error/success branching by hand every time.
It doesn’t echo or return HTML itself, on purpose, it just returns a plain string. That’s what makes it reusable: a shortcode can wrap it in <pre> tags, a future admin page could log it, a REST endpoint could include it in a response during development. The formatting is the caller’s decision, not the helper’s.
The bootstrap you wrote back in Chapter 2 already loads every file in includes automatically via glob(), this new file included, so there’s nothing else to wire up.
Using it from a shortcode
<?php
/**
* Chapter 4: Debugging AI Client Failures
* Usage: add [ai_course_ch4] to any page or post to see the full result
* structure, error or success, for a plain prompt with no special config.
* The reusable ai_course_debug_dump() helper this chapter builds lives in
* 00-helpers.php, not here, since it's meant to be reused by later chapters.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access.
}
function ai_course_ch4_debug_helper() {
if ( ! current_user_can( 'manage_options' ) ) {
return 'This debug view is only shown to admins.';
}
$result = wp_ai_client_prompt( 'Write a haiku about WordPress.' )->generate_text();
return '<pre style="white-space:pre-wrap; background:#f0f0f0; padding:12px;">' . esc_html( ai_course_debug_dump( $result ) ) . '</pre>';
}
add_shortcode( 'ai_course_ch4', 'ai_course_ch4_debug_helper' );
This is deliberately the plainest possible prompt, the same haiku from Chapter 2, no special configuration designed to force a failure. Add [ai_course_ch4] to a page and load it with your provider connected as normal, and you’ll see the success branch: a raw, print_r()-dumped string, not the polished haiku Chapter 2 showed you.
To see the error branch, force a failure the same generic way Chapter 3 already taught: disconnect your provider under Settings > Connectors, then reload the page. You’ll get the full error code, message, and whatever’s sitting in get_error_data(), instead of just a friendly one-liner. Reconnect the provider afterward.
Two things worth noticing in the shortcode itself.
First, current_user_can( 'manage_options' ) gates the whole thing, this prints raw internal detail, not something a random visitor should see on a public page.
Second, notice how little of this function is actually about debugging, one line calls ai_course_debug_dump() and hands the result to <pre>. All the real work lives in the helper, which is exactly the point of building it separately.
Where else to look
ai_course_debug_dump() inside a shortcode is enough for the kind of quick check this chapter walks through, but it’s not the only option, and for anything beyond a one-off test, it’s usually not the best one.
If you’d rather not print debug output onto a page at all, error_log() writes the same string to your server’s error log instead, and pairs well with WP_DEBUG_LOG turned on in wp-config.php if it isn’t already:
error_log( ai_course_debug_dump( $result ) );
Query Monitor, a plugin most WordPress developers already have installed, will also catch PHP errors and warnings without you writing any debug code at all, worth checking there first if something’s failing silently rather than returning a clean WP_Error.
Try it yourself
Take a working shortcode from an earlier chapter, Chapter 2’s haiku example works well, and pass its result through ai_course_debug_dump() before doing anything else with it. Then deliberately break it, disconnect the provider, same as above, and look at the full picture again: code, message, and data. Get used to reaching for the helper before you reach for a guess, in this chapter and every one after it.