Skip to content

JsonException when logging is enabled #120

Description

@pcastellazzi

I am trying to log HTTP requests made by the client. To do it, i enabled the logging middleware on a custom Guzzle instance and pass it to \Typesense\Client.

I have to issues with this approach, first it triggers a JsonException, and secondly, it executes the requests 4 extra times. The JsonException is triggered because the response is read with $response->getBody()->getContents(). It should be (string) $response->getBody(). The first reads the remaining of stream, which when a logger (or another middleware) is present can be empty.

The request multiplication i have no clue. The following example triggers both issues.

<?php

declare(strict_types=1);

require __DIR__.'/vendor/autoload.php';

use Dotenv\Dotenv;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use Monolog\Handler\StreamHandler;
use Monolog\Level;
use Monolog\Logger;
use Typesense\Client as TypesenseClient;

function getGuzzleClient(): GuzzleClient
{
    $logger = new Logger('app');
    $logger->pushHandler(new StreamHandler('php://stdout', Level::Debug));

    $format = ['{method} {uri} HTTP/{version}'];
    $format[] = '{res_headears}';
    $format[] = '{res_body}';
    $format = implode(separator: "\n", array: $format);

    $handler = HandlerStack::create();
    $handler->unshift(Middleware::log($logger, new MessageFormatter($format)));

    return new GuzzleClient(['handler' => $handler]);
}

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

$config = [
    'client' => getGuzzleClient(),
    'api_key' => $_SERVER['TYPESENSE_API_KEY'],
    'nodes' => [[
        'host' => $_SERVER['TYPESENSE_HOST'],
        'port' => $_SERVER['TYPESENSE_PORT'],
        'protocol' => $_SERVER['TYPESENSE_PROTOCOL'],
    ]],
];

$client = new TypesenseClient($config);
var_dump($client->health->retrieve());
$ composer show | grep -iE '(typesense|guzzle)' | cut -c1-41
guzzlehttp/guzzle                  7.10.0
guzzlehttp/promises                2.3.0
guzzlehttp/psr7                    2.9.0
guzzlehttp/uri-template            1.0.5
typesense/typesense-php            6.0.0

$ php --version
PHP 8.4.16 (cli) (built: Dec 18 2025 21:19:25) (NTS)
Copyright (c) The PHP Group
Built by Debian
Zend Engine v4.4.16, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.16, Copyright (c), by Zend Technologies

$ php bug.php
[2026-04-23T03:07:00.310676+00:00] app.INFO: GET http://127.0.0.1:8108/health HTTP/1.1  {"ok":true} [] []
[2026-04-23T03:07:01.311832+00:00] app.INFO: GET http://127.0.0.1:8108/health HTTP/1.1  {"ok":true} [] []
[2026-04-23T03:07:02.312538+00:00] app.INFO: GET http://127.0.0.1:8108/health HTTP/1.1  {"ok":true} [] []
[2026-04-23T03:07:03.313310+00:00] app.INFO: GET http://127.0.0.1:8108/health HTTP/1.1  {"ok":true} [] []
PHP Fatal error:  Uncaught JsonException: Syntax error in /app/source/vendor/typesense/typesense-php/src/ApiCall.php:273
Stack trace:
#0 /app/source/vendor/typesense/typesense-php/src/ApiCall.php(273): json_decode()
#1 /app/source/vendor/typesense/typesense-php/src/ApiCall.php(108): Typesense\ApiCall->makeRequest()
#2 /app/source/vendor/typesense/typesense-php/src/Health.php(39): Typesense\ApiCall->get()
#3 /app/source/bug.php(47): Typesense\Health->retrieve()
#4 {main}
  thrown in /app/source/vendor/typesense/typesense-php/src/ApiCall.php on line 273

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions