Conditional query tags do not work before the query is run. Before then, they always return false

Where can I find the WP initializing process documentation?

This should help:

So, here are the steps WordPress uses to decide what posts or pages to
display on a page, and display them:

  1. When a visitor first clicks on or types a URL for a page that is part of your blog, WordPress starts by running a few core files
    (wp-config.php, wp-settings.php, etc.) If you are interested in
    the specifics of the file loading order, start at index.php and
    follow the chain of files as each PHP file includes/requires
    additional PHP files (or read this excellent post at
  2. WordPress loads and initializes any plugins you have activated (calls the plugin init actions).
  3. WordPress loads the “text domain” for internationalization, and the functions.php file from the currently active theme.
  4. WordPress runs the wp() function (in wp-includes/functions.php), which calls $wp->main() ($wp is an
    object of class WP, which is defined in wp-includes/class-wp.php).
    This tells WordPress to:

    1. Parse the URL into a query specification using WP->parse_request() — more on that
    2. Set all the is_ variables that are used by Conditional Tags
      using $wp_query->parse_query() ($wp_query is an object of class
      WP_Query, which is defined in wp-includes/query.php). Note that in
      spite of this function’s name, in this case WP_Query->parse_query
      doesn’t actually do any parsing for us, since that is done before-hand
      by WP->parse_request().
    3. Convert the query specification into a MySQL database query, and run the database query to get the list of posts, in function
      WP_Query->get_posts(). Save the posts in the $wp_query object to
      be used in the WordPress Loop.
    4. Handle 404 errors.
    5. Send the blog’s HTTP headers.
    6. Set up some variables for the WordPress Loop.

So generally, on the front-end (non wp-admin side), you can call the conditional tags like is_single() only on or after the parse_query hook and later hooks like pre_get_posts, wp, template_redirect, wp_head and wp_enqueue_scripts (yes, they are in that order).

Therefore if for example you used an early hook like plugins_loaded like so, then you’d get the error in question:

add_action( 'plugins_loaded', function () {
    error_log( is_single() );
} );

So I hope this answer helps you find the right hook.