← Alle berichten

Half a letter wiped the whole answer

An async request returned status 200 with a body of one byte. No error page, nothing in data/errors.json, nothing in the server log. It happened on three of eleven languages and on no others, which is the kind of pattern that looks like data and turns out to be bytes.

It was bytes. When a translation is missing, the lang resource writes the source line to the debug log, trimmed to keep the log readable:

strlen($line) > 20 ? substr($line, 0, 18).'...' : $line

substr counts bytes, so on a line where the nineteenth byte sat inside a multi-byte letter it cut the letter in half. In debug mode those lines are attached to the apply commands, and json_encode refuses invalid UTF-8 and returns false. The call site then did this:

$body = (string)json_encode($cmds, jsonFlat);

(string)false is the empty string, so a hard failure became a successful empty answer. The languages that broke were exactly the ones with gaps in their translation file.

Two fixes, because there were two faults. The resource now trims by characters with mb_substr. And the call site no longer casts:

$body = json_encode($cmds, jsonFlat);
$body === false && error('apply() cannot be encoded: '.json_last_error_msg());

JSON_INVALID_UTF8_SUBSTITUTE was the tempting one-line answer and it is the wrong one. It would have hidden this class of fault rather than reported it, it does nothing for the other ways json_encode can fail, and jsonFlat also carries the daemon protocol and stored bodies, where a replacement character written to disk is worse than a refusal.

Engine 1.0.

We gebruiken essentiële cookies om deze site te laten werken. Met uw toestemming gebruiken we ook analytics om de site te verbeteren.