magento2-40825: Catalog Products List widget failing on malformed UTF-8 in query string
Community fix magento2-40825 merged into magento/magento2 on 2026-06-23, not in a release yet; applies cleanly to 34 releases from 2.4.6 to 2.4.9.
Fixes Catalog Products List widget failing on malformed UTF-8 in query string edited
- Pull request title
- Regression: Non UTF-8 encoded URI component still throws "Unable to serialize value" in CatalogWidget on 2.4.7-p5
- Pull request
- magento/magento2#40825
- Issues
- #40824 human
- Author
- @lbajsarowicz
- Merged
- 2026-06-23
- Fixed in
- no release yet
- Reported on
- 2.4.7-p5
- Categories
- Content
- Components
- magento/module-catalog-widget
Labels
- Area
- Content / CMS
- Component
- Widget
- Priority
- P2
- Severity
- —
- Reported on (labels)
- 2.4.7-p5
Issue
Title and steps come from the upstream issue and pull request.
Description
"Sorry, we cannot generate the content...", localized) and the following entry is logged:Steps to reproduce
2. Open that page with a malformed UTF-8 byte sequence in a query parameter, e.g.:
-
https://example.test/?q=%C0%AF (overlong UTF-8 slash)-
https://example.test/?dclid=%EDclid-
https://example.test/?utm_source=%E0-
https://example.test/?fbclid=foo% (dangling percent)3. Observe the rendered page and
var/log/system.log.These URLs occur in the wild from truncated Facebook / Google Ads tracking parameters (
fbclid, gclid, dclid, utm_*), broken share buttons, and bot scanners.Expected result
Actual result
"Sorry, we cannot generate the content...", localized) and the following entry is logged:main.CRITICAL: InvalidArgumentException: Unable to serialize value. Error: Malformed UTF-8 characters, possibly incorrectly encoded in vendor/magento/framework/Serialize/Serializer/Json.php:26Abbreviated stack trace:
#0 vendor/magento/module-catalog-widget/Block/Product/ProductsList.php(235):
Magento\Framework\Serialize\Serializer\Json->serialize()
#5 vendor/magento/framework/View/Element/AbstractBlock.php(1063):
ProductsList->getCacheKeyInfo()
#6 AbstractBlock.php(1150): AbstractBlock->getCacheKey()
#7 AbstractBlock.php(676): AbstractBlock->_loadCache()
#8 Interceptor->___callParent() → toHtml()
...
#82 vendor/magento/framework/App/Http.php(120): renderResult()
#92 pub/index.php(30): Bootstrap->run()### Root causeMagento\CatalogWidget\Block\Product\ProductsList::getCacheKeyInfo() (line 235 of current 2.4-develop) passes raw $_GET (via $this->getRequest()->getParams()) to the serializer:return [
...
$this->json->serialize($this->getRequest()->getParams()),
...
];Magento\Framework\Serialize\Serializer\Json::serialize() calls json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) with no JSON_INVALID_UTF8_SUBSTITUTE / JSON_INVALID_UTF8_IGNORE flag. Any byte sequence in $_GET that is not valid UTF-8 causes json_encode to return false with JSON_ERROR_UTF8, which the serializer rethrows as InvalidArgumentException.Because
getCacheKeyInfo() is called from AbstractBlock::getCacheKey() → _loadCache() → toHtml(), the entire block fails to render and Magento falls back to the generic error template.The same underlying defect surfaces in any other code path that serializes user-controlled input (request params, raw cookie values, certain redirect URLs). See also the ReCaptcha variant reported in #30486.
### Related / prior reports
- #23760 — original report (2019). Marked as fixed in 2.4.3 via internal ticket
MC-23846, but follow-up from @edas11 (2025-05-06) confirms reproduction on 2.4.7-p5 and 2.4.4-p13. This issue is filed to track the regression / incomplete fix.- #30486 — same root cause surfaced via
Magento_ReCaptcha. Closed 2021.- #17934 — analogous problem in checkout
getSerializedCheckoutConfig (silent json_encode failure).- #23356, #37326, #40304 — additional UTF-8 / multibyte handling regressions in core.
### Suggested directions (not a fix proposal)
Listed only to clarify scope of the regression:
-
Magento\Framework\Serialize\Serializer\Json::serialize() — pass JSON_INVALID_UTF8_SUBSTITUTE (or wrap in a guard that returns a safe placeholder).-
Magento\CatalogWidget\Block\Product\ProductsList::getCacheKeyInfo() — sanitize / hash $_GET instead of serializing it raw. Including the full $_GET in the cache key is also a separate performance / cache-fragmentation concern, since any unique URL parameter creates a new cache entry.### Severity / impact
- Reliability: any URL with malformed UTF-8 from third-party traffic sources renders an error region instead of the home / category / CMS page where the widget is placed.
- Reachability: trivial. A single crafted GET parameter is enough; no auth, no preconditions beyond the widget being on the page.
- Observability cost: every hit logs a
CRITICAL to system.log, which can drown application logs under bot traffic.Taken from the upstream issue.
Error signatures
- main.CRITICAL: InvalidArgumentException: Unable to serialize value.
- Error: Malformed UTF-8 characters, possibly incorrectly encoded
- `Magento\Framework\Serialize\Serializer\Json::serialize()` calls `json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)` with no `JSON_INVALID_UTF8_SUBSTITUTE` / `JSON_INVALID_UTF8_IGNO
Code match per tag
Each tag was checked with git apply --check against that tag's files. A clean match means the change applies; it is not a test result. Tags that already contain the fix are marked.
| Line | Code match per tag | Tests |
|---|---|---|
| 2.4.6 | 2.4.6 clean 2.4.6-p1 clean 2.4.6-p2 clean 2.4.6-p3 clean 2.4.6-p4 clean 2.4.6-p5 clean 2.4.6-p6 clean 2.4.6-p7 clean 2.4.6-p8 clean 2.4.6-p9 clean 2.4.6-p10 clean 2.4.6-p11 clean 2.4.6-p12 clean 2.4.6-p13 clean 2.4.6-p14 clean 2.4.6-p15 clean | 2.4.6: no test data 2.4.6-p1: no test data 2.4.6-p2: no test data 2.4.6-p3: no test data 2.4.6-p4: no test data 2.4.6-p5: no test data 2.4.6-p6: no test data 2.4.6-p7: no test data 2.4.6-p8: no test data 2.4.6-p9: no test data 2.4.6-p10: no test data 2.4.6-p11: no test data 2.4.6-p12: no test data 2.4.6-p13: no test data 2.4.6-p14: no test data 2.4.6-p15: no test data |
| 2.4.7 | 2.4.7 clean 2.4.7-p1 clean 2.4.7-p2 clean 2.4.7-p3 clean 2.4.7-p4 clean 2.4.7-p5 clean 2.4.7-p6 clean 2.4.7-p7 clean 2.4.7-p8 clean 2.4.7-p9 clean 2.4.7-p10 clean | 2.4.7: no test data 2.4.7-p1: no test data 2.4.7-p2: no test data 2.4.7-p3: no test data 2.4.7-p4: no test data 2.4.7-p5: no test data 2.4.7-p6: no test data 2.4.7-p7: no test data 2.4.7-p8: no test data 2.4.7-p9: no test data 2.4.7-p10: test files do not apply to this releaseunit: could not run before, could not run after |
| 2.4.8 | 2.4.8 clean 2.4.8-p1 clean 2.4.8-p2 clean 2.4.8-p3 clean 2.4.8-p4 clean 2.4.8-p5 clean | 2.4.8: no test data 2.4.8-p1: no test data 2.4.8-p2: no test data 2.4.8-p3: no test data 2.4.8-p4: no test data 2.4.8-p5: test files do not apply to this releaseunit: could not run before, could not run after |
| 2.4.9 | 2.4.9 clean | 2.4.9: test could not run before the patch, passes afterunit: could not run before, passes after |
Triage
Model @cf/cloudflare/clef. Probability this is a bug fix: 98.3%. Probability it is security relevant: 3.6%.
Show the model's answers and probabilities
| Question | Answer | Probabilities | Confidence |
|---|---|---|---|
| Change kind | bugfix | bugfix 95.6%, refactor 1.5%, tests_only 1.0%, feature 0.7%, dependency 0.6%, docs_only 0.5% | 89.7% |
| Area | catalog | catalog 34.6%, framework 31.1%, frontend 16.3% | 15.2% |
| Reported version | 2.4.7-p5 | 2.4.7-p5 51.7%, 2.4.7 8.7%, 2.4.4-p13 8.7% | 27.6% |
| Scope | 0.74 of 2 | 1 53.4%, 0 36.4%, 2 10.1% | 14.3% |
| Risk | 0.10 of 2 | 0 92.1%, 1 5.8%, 2 2.1% | 77.7% |
| Worth backporting | 1.82 of 2 | 2 85.2%, 1 11.7%, 0 3.1% | 61.0% |
Download
For cweagans/composer-patches, choose a version below and download the bundle. Copy its magento2-40825/ folder into patches/composer/, merge composer.patches.json into composer.json, then run composer install. Test files are always removed; paths are relative to each package root, using the default -p1 level.
Bundle README (what the ZIP ships)
# magento2-40825 Community fix merged upstream into magento/magento2, adapted by magento.watch. This is not a patch published by Adobe. Pull request: https://github.com/magento/magento2/pull/40825 Issue: https://github.com/magento/magento2/issues/40824 Author: @lbajsarowicz Source commit: c80cabffe0e0423cedfbf5845adfb991f69bdf9e Modifications: test files and documentation removed, paths rewritten relative to each Composer package. Licence: OSL-3.0 / AFL-3.0, as the original Magento Open Source code. Maintainer: Łukasz Bajsarowicz (@lbajsarowicz)
Licence: Magento Open Source code under OSL-3.0 and AFL-3.0. The bundle carries the original author, source commit and the list of modifications.
