Skip to content

AI Request Logs: HTTP error responses (4xx/5xx) are recorded as "success" #1032

Description

@nielash

Description

The AI Request Logs screen records every provider request that gets an HTTP response as success, whatever the status code. A 503 or 429 from the provider shows as a green "✓ success" row. Neither the status code nor the provider's error message is stored. As a result, the log looks healthy while a feature is failing every time.

In Logging_Http_Transporter::send() (includes/Logging/Logging_Http_Transporter.php, unchanged between 1.3.0 and trunk), $status starts as 'success' and changes only in the catch ( Throwable $e ) branch:

$status = 'success';
try {
    $response = $this->transporter->send( $request, $options );
    $log_data = $this->extract_response_data( $response, $log_data );
    return $response;
} catch ( Throwable $e ) {
    $status    = 'error';
    $error_msg = $e->getMessage();
    throw $e;
} finally {
    $log_data['status']        = $status;
    $log_data['error_message'] = $error_msg;
    $this->log_manager->log( $log_data );
}

The SDK's HttpTransporter::send() throws only for PSR-18 network or client exceptions. A non-2xx response comes back as an ordinary Response. The provider rejects it later, after the log row has already been written. For example, GoogleTextGenerationModel::generateTextResult() calls ResponseUtil::throwIfNotSuccessful( $response ) right after send() returns. That throws a ServerException, which reaches the user as prompt_upstream_server_error, but the log already says success.

A second, smaller problem appears on the same rows. Log_Data_Extractor::detect_request_kind() returns metadata for any path containing /models/. Every Gemini generation URL has the form .../v1beta/models/{model}:generateContent, so all Google text requests are labeled Request Kind: Metadata.

Step-by-step reproduction instructions

  1. Connect the Google provider and enable Request Logging and Image Generation.
  2. Trigger a request that the provider rejects. The easiest way is to exceed a free-tier quota, which returns 429. I also hit a deterministic 503 from gemini-3.6-flash on some prompt content.
  3. The editor shows the error, e.g.
    {"code":"prompt_upstream_server_error","message":"Service Unavailable (503) - This model is currently experiencing high demand. ...","data":{"status":503,"exception_class":"WordPress\\AiClient\\Providers\\Http\\Exception\\ServerException"}}
  4. Open Tools > AI Request Logs and view the matching row.

Expected: status error, the HTTP status code, and the provider's error message.

Actual: ✓ success, no error message, no token counts, no output preview, and Request Kind Metadata.

In my case the 503 came back on every attempt over several days. I only found the cause by capturing the request body and replaying it outside the plugin. If the log had shown error with the 503 message, I wouldn't have needed to.

Suggested fix

Response already provides isSuccessful() and getStatusCode(). After a response comes back:

$response = $this->transporter->send( $request, $options );
$log_data = $this->extract_response_data( $response, $log_data );

if ( ! $response->isSuccessful() ) {
    $status    = 'error';
    $error_msg = sprintf( 'HTTP %d', $response->getStatusCode() );
    $data      = $response->getData();
    if ( isset( $data['error']['message'] ) && is_string( $data['error']['message'] ) ) {
        $error_msg .= ': ' . $data['error']['message'];
    }
}

Storing the status code in its own column (or in context) would also make these rows filterable. For detect_request_kind(), checking for a :generateContent / :streamGenerateContent suffix before the /models/ rule would fix the Gemini mislabel.

Related

Screenshots, screen recording, code snippet

No response

Environment info

  • WordPress 7.1
  • AI plugin 1.3.0, AI Provider for Google 1.1.1
  • PHP 8.5

Please confirm that you have searched existing issues in the repo.

  • Yes

Please confirm that you have tested with all plugins deactivated except the AI plugin.

  • Yes

Please confirm which theme type you used for testing.

  • Block
  • Classic
  • Hybrid (e.g. classic with theme.json)
  • Not sure

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    [Type] BugSomething isn't working

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions