Skip to content

Fix fatal error when pre_http_request response is never logged#1071

Open
trajche wants to merge 1 commit intojohnbillion:developfrom
trajche:fix/pre-http-request-untracked-response
Open

Fix fatal error when pre_http_request response is never logged#1071
trajche wants to merge 1 commit intojohnbillion:developfrom
trajche:fix/pre-http-request-untracked-response

Conversation

@trajche
Copy link

@trajche trajche commented Feb 21, 2026

Fixes #811

Root cause

QM hooks both http_request_args and pre_http_request at priority 9999. When a plugin hooks pre_http_request at a higher priority (e.g. 10000), the execution order is:

  1. QM's filter_pre_http_request runs at priority 9999 → sees $response === false, returns early without logging
  2. The other plugin's callback runs at priority 10000 → intercepts, returns a non-false value
  3. WordPress short-circuits the actual HTTP request → http_api_debug never fires

Result: the request is stored in $this->http_requests (via http_request_args) but nothing is ever written to $this->http_responses. When process() accesses $this->http_responses[$key], PHP 8.x throws ErrorException: Undefined array key.

Known triggers: wp-china-yes, Polylang Pro update checks, security plugins that block external requests.

Fix

Check whether a response was captured before accessing it. If not, synthesise a fallback with http_request_not_executed the same WP_Error code already used for nested-request edge cases (line 297) and already in the default qm/collect/silent_http_errors list, so it won't generate a spurious alert.

How to reproduce

Drop this in mu-plugins/qm-bug-repro.php and visit /?trigger_qm_bug=1:

<?php
add_filter( 'pre_http_request', function( $preempt, $args, $url ) {
    if ( str_contains( $url, 'qm-bug-test' ) ) {
        return new WP_Error( 'intercepted', 'Simulated late interception' );
    }
    return $preempt;
}, 10000, 3 );

add_action( 'init', function() {
    if ( isset( $_GET['trigger_qm_bug'] ) ) {
        wp_remote_get( 'https://example.com/qm-bug-test' );
    }
} );

Co-authored with Claude ^

When a plugin hooks `pre_http_request` at a priority higher than QM's
(9999), QM's own `filter_pre_http_request` callback runs first and sees
no interception yet (response is still false). The later plugin then
intercepts and returns a non-false value, causing WordPress to
short-circuit the request. This means `http_api_debug` never fires, so
no entry is ever added to `$this->http_responses` for that key.

When `process()` later iterates `$this->http_requests` and accesses
`$this->http_responses[$key]`, the missing key causes an
`ErrorException: Undefined array key` on PHP 8.x.

Fix by checking whether the response was captured before accessing it.
If not, synthesise a fallback using `http_request_not_executed` — the
same error code already used for nested-request edge cases (line 297)
and already present in the default `qm/collect/silent_http_errors` list,
so it won't generate a spurious alert.

Fixes johnbillion#811
@johnbillion johnbillion changed the base branch from trunk to develop February 21, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant