laravel-efficient-uuid icon indicating copy to clipboard operation
laravel-efficient-uuid copied to clipboard

`Malformed UTF-8 characters` error when a QueryException is thrown

Open AmirrezaNasiri opened this issue 6 years ago • 6 comments
trafficstars

I've faced the same problem described here and here (but that package has been abandoned).

The problem occurs because the exception can't be formatted to normal JSON data since it contains binary. The problem can be solved by doing these changes in illuminate\database\QueryException.php:

$this->message = $this->formatMessage($sql, $bindings, $previous);

To:

$this->message = utf8_encode($this->formatMessage($sql, $bindings, $previous));

But it's defiantly not a good idea. Any idea about solving it?

AmirrezaNasiri avatar Jun 06 '19 23:06 AmirrezaNasiri

Have had this issue myself, too.

Can't think of a good enough reason to propose changing queryexception at the framework end.

Custom exception handler? Seems like quite a jump for what isn't an especially common issue.

stevesweets avatar Aug 12 '19 10:08 stevesweets

Hi there, I'm having this issue too. What I did to have the original error message in the JSON response is this:

In app/Exceptions/Handler.php

    public function render($request, Throwable $exception)
    {
        if ($exception instanceof QueryException && $request->isJson()) {
            $message = mb_convert_encoding($exception->getMessage(), 'ASCII');
            throw new Exception($message);
        }

        return parent::render($request, $exception);
    }

This is working quite well as a workaround.

blitux avatar Apr 24 '20 04:04 blitux

Just another workaround:

In app/Exceptions/Handler.php override prepareJsonResponse method

    protected function prepareJsonResponse($request, Throwable $e)
    {
        $exceptionArray = $this->convertExceptionToArray($e);

        $exceptionArray['message'] = mb_convert_encoding($exceptionArray['message'], 'ASCII');

        return new JsonResponse(
            $exceptionArray,
            $this->isHttpException($e) ? $e->getStatusCode() : 500,
            $this->isHttpException($e) ? $e->getHeaders() : [],
            JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
        );
    }

maxcelos avatar Jul 17 '20 16:07 maxcelos

A solution to this issue could be:

  1. Create a custom Hander extending Illuminate\Foundation\Exceptions\Handler inside this package with the prepareJsonResponse method suggested above;

  2. Bind it to Illuminate\Contracts\Debug\ExceptionHandler in the package service provider, using a class defined on config file;

    // src/LaravelEfficientUuidServiceProvider.php
    public function boot()
    {
        $this->app->bind(ExceptionHandler::class, config('dyryndadb.error_handler'));
    }
  1. Provide a publishable config file so the developer can use their own implementation if it conflicts with any other already existing error handler customization.
return [
    ...
    'error_handler' => Dyrynda\Database\Exceptions\Handler::class,
];

@michaeldyrynda and others, would something like this be a welcomed PR or do you think this is too much aggressive.

maxcelos avatar Jul 17 '20 16:07 maxcelos

I'd much rather document this and provide one concrete way to address it.

Providing an exception handler is tricky because users of the package possibly won't be able to just use it due to modification of their own app's handler.

michaeldyrynda avatar Jul 17 '20 22:07 michaeldyrynda

Hi there, I'm having this issue too. What I did to have the original error message in the JSON response is this:

In app/Exceptions/Handler.php

    public function render($request, Throwable $exception)
    {
        if ($exception instanceof QueryException) {
            $message = mb_convert_encoding($exception->getMessage(), 'ASCII');
            throw new Exception($message);
        }

        return parent::render($request, $exception);
    }

This is working quite well as a workaround.

Worked for me too. But I needed to remove $request->isJson() on if.