Skip to content

Substitute invalid UTF-8 in JSON error renderer output - #3465

Merged
akrabat merged 4 commits into
slimphp:4.xfrom
iliaal:fix/json-error-renderer-invalid-utf8
Aug 29, 2026
Merged

Substitute invalid UTF-8 in JSON error renderer output#3465
akrabat merged 4 commits into
slimphp:4.xfrom
iliaal:fix/json-error-renderer-invalid-utf8

Conversation

@iliaal

@iliaal iliaal commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

json_encode() returns false when any string in the payload contains an invalid UTF-8 sequence, so a JSON error response for an exception whose message or title carries raw binary data (invalid-UTF-8 user input echoed into exception messages is the common path) was emitted as a zero-length body under Content-Type: application/json. Strict API clients then fail to parse the empty body and the actual error information is silently discarded.

This adds JSON_INVALID_UTF8_SUBSTITUTE so invalid byte sequences are replaced with the UTF-8 replacement character instead of failing the whole encode. The renderer output stays valid JSON in all cases.

Reproduction on 4.x before this change:

$renderer = new \Slim\Error\Renderers\JsonErrorRenderer();
$output = $renderer(new \RuntimeException("bad \xB1\x31 bytes"), true);
var_dump(strlen($output)); // int(0)

json_encode() returns false for strings with invalid UTF-8 sequences,
so exception messages or titles carrying raw binary data produced an
empty response body under a JSON content type. Pass
JSON_INVALID_UTF8_SUBSTITUTE so invalid sequences are replaced with
the UTF-8 replacement character instead of discarding the whole
payload.
@coveralls

coveralls commented Aug 25, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 99.456%. remained the same — iliaal:fix/json-error-renderer-invalid-utf8 into slimphp:4.x

@akrabat

akrabat commented Aug 25, 2026

Copy link
Copy Markdown
Member

I changed line 41 of JsonErrorRenderer back to JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES and the test didn't fail.

There's a couple of problems with the test.

First, the false in $output = $renderer->__invoke($exception, false); means that the error details are not rendered, and so only the title ("Slim Application Error") is encoded, so the JSON returned is:

{
    "message": "Slim Application Error"
}

which doesn't include the message we're looking for.

Secondly asserting that the key message exists in the array doesn't test that the invalid UTF-8 is correctly encoded in the JSON.

Can you update the test to prove that the change works?

@akrabat akrabat self-assigned this Aug 25, 2026
The previous test invoked the renderer with displayErrorDetails=false,
so only the title was encoded and the invalid exception message never
reached json_encode. Assert the decoded exception message contains
U+FFFD so the test fails if JSON_INVALID_UTF8_SUBSTITUTE is removed.
@iliaal

iliaal commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

displayErrorDetails=false only encoded the title, so the invalid UTF-8 never reached json_encode. I changed the test to pass true and assert the decoded exception message is "Invalid \u{FFFD}1 UTF-8 sequence". That assertion fails if JSON_INVALID_UTF8_SUBSTITUTE is dropped.

@akrabat akrabat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@akrabat
akrabat merged commit 8e77282 into slimphp:4.x Aug 29, 2026
10 checks passed
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.

3 participants