[BUGFIX] Survive a null or unknown code language - #18
Open
davidsteeb wants to merge 2 commits into
Open
davidsteeb wants to merge 2 commits into
davidsteeb wants to merge 2 commits into
Conversation
code_language is a nullable column, so a record can hold NULL where the TCA default would have written an empty string. "??" substitutes only for NULL, so the falsy check read that NULL as "a language was chosen" and passed it to the highlighter. There it ends the request: on PHP 8.4 highlight() throws DomainException: Unknown language: "", and on 8.5 the lookup trips "Using null as an array offset" first, which TYPO3 turns into an exception. Either way the page returns a 500. Normalise the value to a string before deciding, so NULL takes the autodetect branch like an empty string does.
bmack
approved these changes
Sep 24, 2026
highlight() throws DomainException when the given language is not registered, and nothing caught it, so a stored value that no longer resolves ended the request with a 500 - the same failure as a null language, just from the other direction. A language can stop resolving without the record changing: it may be dropped from the registered set, or the record may arrive from an installation that had it. Catch that one exception and detect the language instead. A language that does resolve is still used as it was.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A stored
code_languagevalue can take the whole page down with a 500, in two ways.A null language
code_languageis declared ascode_language textinext_tables.sql, so the column is nullable. The TCA field hasdefault => '', but a record can still end up withNULL, and the branch did not survive it:??substitutes only forNULL, so it yieldstrue, the falsy check reads that as "a language was chosen", andNULLgoes straight to the highlighter. What happens next depends on the PHP version, but the page dies either way:DomainException: Unknown language: ""fromHighlighter::highlight()Using null as an array offset is deprecatedinHighlighter::getLanguage(), turned into an exception by TYPO3's error handlerNormalising the value to a string before deciding puts
NULLon the autodetect branch, exactly where an empty string already goes.A language that no longer resolves
highlight()throwsDomainExceptionwhen the name is not registered, and nothing caught it. A record can stop resolving without ever being edited — the language may be dropped from the registered set, or the record may arrive from an installation that had it. Same outcome as above: a stored value ends the request.That one exception is now caught and the language detected instead. A language that does resolve is still used as it was, so this is not a blanket catch.
Verified
Against a TYPO3 v14 site on PHP 8.5, one content element, only
code_languagevaried:code_languageNULL'''klingonisch'(not registered)'bash'bashThe last row is the one that matters for the catch: a language that resolves is untouched. Elements that already carried a valid language render exactly as before, and the recovered elements produce the regular markup with an
hljsclass on the detected language.