{"data":{"id":"magento2-40825","source":"github-pr","sourceRef":"magento/magento2#40825","title":"Regression: Non UTF-8 encoded URI component still throws \"Unable to serialize value\" in CatalogWidget on 2.4.7-p5","pr":{"number":40825,"url":"https://github.com/magento/magento2/pull/40825","author":"lbajsarowicz","mergedAt":"2026-06-23T07:04:14Z","mergeCommit":"48151aafbfd28d8ec9d79ccf14f8085d58270a00","headCommit":"c80cabffe0e0423cedfbf5845adfb991f69bdf9e","baseRef":"2.4-develop","diffSha256":"4852f14892afb8e6ea277c8bda9da692f3c8b05fa1cee2ab06d7058223406883"},"issues":[{"number":40824,"url":"https://github.com/magento/magento2/issues/40824","title":"Regression: Non UTF-8 encoded URI component still throws \"Unable to serialize value\" in CatalogWidget on 2.4.7-p5","labels":["Area: Content / CMS","Component: Widget","Issue: Confirmed","Priority: P2","Progress: PR Created","Progress: done","Reported on 2.4.7-p5","Reproduced on 2.4.x"],"kind":"human"}],"fixedIn":null,"containingTags":[],"reportedOn":"2.4.7-p5","codeMatch":{"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.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.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.9":"clean"},"affectedVersions":["2.4.6","2.4.6-p1","2.4.6-p2","2.4.6-p3","2.4.6-p4","2.4.6-p5","2.4.6-p6","2.4.6-p7","2.4.6-p8","2.4.6-p9","2.4.6-p10","2.4.6-p11","2.4.6-p12","2.4.6-p13","2.4.6-p14","2.4.6-p15","2.4.7","2.4.7-p1","2.4.7-p2","2.4.7-p3","2.4.7-p4","2.4.7-p5","2.4.7-p6","2.4.7-p7","2.4.7-p8","2.4.7-p9","2.4.7-p10","2.4.8","2.4.8-p1","2.4.8-p2","2.4.8-p3","2.4.8-p4","2.4.8-p5","2.4.9"],"components":["magento/module-catalog-widget"],"files":[{"path":"app/code/Magento/CatalogWidget/Block/Product/ProductsList.php","change":"modified","package":"magento/module-catalog-widget"}],"stripped":{"tests":["app/code/Magento/CatalogWidget/Test/Unit/Block/Product/ProductsListTest.php"],"docs":[],"outsideCode":[]},"linesChanged":27,"mergeBatched":false,"excluded":null,"sections":{"description":"Widget output is replaced by the generic CMS fallback message (`\"Sorry, we cannot generate the content...\"`, localized) and the following entry is logged:","stepsToReproduce":"1. Add a \"Catalog Products List\" widget to any CMS page (e.g. homepage).\n2. Open that page with a malformed UTF-8 byte sequence in a query parameter, e.g.:\n   - `https://example.test/?q=%C0%AF`   (overlong UTF-8 slash)\n   - `https://example.test/?dclid=%EDclid`\n   - `https://example.test/?utm_source=%E0`\n   - `https://example.test/?fbclid=foo%`  (dangling percent)\n3. Observe the rendered page and `var/log/system.log`.\n\nThese URLs occur in the wild from truncated Facebook / Google Ads tracking parameters (`fbclid`, `gclid`, `dclid`, `utm_*`), broken share buttons, and bot scanners.","expectedResult":"Widget renders normally. Malformed UTF-8 in the query string must not break server-side block rendering.","actualResult":"Widget output is replaced by the generic CMS fallback message (`\"Sorry, we cannot generate the content...\"`, localized) and the following entry is logged:\n\n```\nmain.CRITICAL: InvalidArgumentException: Unable to serialize value.\nError: Malformed UTF-8 characters, possibly incorrectly encoded\n  in vendor/magento/framework/Serialize/Serializer/Json.php:26\n```\n\nAbbreviated stack trace:\n\n```\n#0  vendor/magento/module-catalog-widget/Block/Product/ProductsList.php(235):\n      Magento\\Framework\\Serialize\\Serializer\\Json->serialize()\n#5  vendor/magento/framework/View/Element/AbstractBlock.php(1063):\n      ProductsList->getCacheKeyInfo()\n#6  AbstractBlock.php(1150): AbstractBlock->getCacheKey()\n#7  AbstractBlock.php(676):  AbstractBlock->_loadCache()\n#8  Interceptor->___callParent() → toHtml()\n...\n#82 vendor/magento/framework/App/Http.php(120): renderResult()\n#92 pub/index.php(30): Bootstrap->run()\n```\n\n### Root cause\n\n`Magento\\CatalogWidget\\Block\\Product\\ProductsList::getCacheKeyInfo()` (line 235 of current `2.4-develop`) passes raw `$_GET` (via `$this->getRequest()->getParams()`) to the serializer:\n\n```php\nreturn [\n    ...\n    $this->json->serialize($this->getRequest()->getParams()),\n    ...\n];\n```\n\n`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`.\n\nBecause `getCacheKeyInfo()` is called from `AbstractBlock::getCacheKey()` → `_loadCache()` → `toHtml()`, the entire block fails to render and Magento falls back to the generic error template.\n\nThe 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.\n\n### Related / prior reports\n\n- #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.\n- #30486 — same root cause surfaced via `Magento_ReCaptcha`. Closed 2021.\n- #17934 — analogous problem in checkout `getSerializedCheckoutConfig` (silent `json_encode` failure).\n- #23356, #37326, #40304 — additional UTF-8 / multibyte handling regressions in core.\n\n### Suggested directions (not a fix proposal)\n\nListed only to clarify scope of the regression:\n\n- `Magento\\Framework\\Serialize\\Serializer\\Json::serialize()` — pass `JSON_INVALID_UTF8_SUBSTITUTE` (or wrap in a guard that returns a safe placeholder).\n- `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.\n\n### Severity / impact\n\n- **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.\n- **Reachability**: trivial. A single crafted GET parameter is enough; no auth, no preconditions beyond the widget being on the page.\n- **Observability cost**: every hit logs a `CRITICAL` to `system.log`, which can drown application logs under bot traffic.","source":"issue"},"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"],"labels":{"area":["Content / CMS"],"component":["Widget"],"priority":"P2","severity":null,"reportedOn":["2.4.7-p5"]},"categories":["Content"],"triage":{"model":"@cf/cloudflare/clef","requestHash":"ef5a2ec9b78f64170ccb818b8d0cf78b6a5aa154999fb441b4c70d4c33a4c071","isBugfix":0.9827,"changeKind":{"choice":"bugfix","probabilities":{"bugfix":0.9558,"feature":0.0073,"refactor":0.0148,"tests_only":0.0104,"docs_only":0.0053,"dependency":0.0064},"confidence":0.8968},"scope":{"score":0.7369,"probabilities":{"0":0.3644,"1":0.5343,"2":0.1013},"confidence":0.1428},"risk":{"score":0.101,"probabilities":{"0":0.9206,"1":0.0579,"2":0.0215},"confidence":0.7768},"area":{"choice":"catalog","probabilities":{"catalog":0.3465,"checkout":0.0151,"customer":0.0106,"admin":0.027,"graphql_api":0.0101,"framework":0.3105,"frontend":0.1627,"other":0.1175},"confidence":0.152},"securityRelevant":0.0364,"reportedVersion":{"choice":"2.4.7-p5","probabilities":{"2.4.0":0.0017,"2.4.0-p1":0.0019,"2.4.1":0.0017,"2.4.1-p1":0.0018,"2.4.2":0.0017,"2.4.2-p1":0.0019,"2.4.2-p2":0.0018,"2.4.3":0.002,"2.4.3-p1":0.0022,"2.4.3-p2":0.0023,"2.4.3-p3":0.0023,"2.4.4":0.0023,"2.4.4-p1":0.0023,"2.4.4-p10":0.0028,"2.4.4-p11":0.0025,"2.4.4-p12":0.0049,"2.4.4-p13":0.0871,"2.4.4-p14":0.0019,"2.4.4-p15":0.0025,"2.4.4-p16":0.0022,"2.4.4-p17":0.0028,"2.4.4-p18":0.0026,"2.4.4-p2":0.0017,"2.4.4-p3":0.0017,"2.4.4-p4":0.0017,"2.4.4-p5":0.0019,"2.4.4-p6":0.0018,"2.4.4-p7":0.0024,"2.4.4-p8":0.0027,"2.4.4-p9":0.0022,"2.4.5":0.002,"2.4.5-p1":0.002,"2.4.5-p10":0.0023,"2.4.5-p11":0.0027,"2.4.5-p12":0.0033,"2.4.5-p13":0.0028,"2.4.5-p14":0.0026,"2.4.5-p15":0.0026,"2.4.5-p16":0.003,"2.4.5-p17":0.0027,"2.4.5-p2":0.0018,"2.4.5-p3":0.002,"2.4.5-p4":0.0021,"2.4.5-p5":0.0023,"2.4.5-p6":0.0023,"2.4.5-p7":0.0026,"2.4.5-p8":0.0024,"2.4.5-p9":0.0019,"2.4.6":0.0034,"2.4.6-p1":0.0037,"2.4.6-p10":0.0038,"2.4.6-p11":0.0052,"2.4.6-p12":0.0046,"2.4.6-p13":0.0049,"2.4.6-p14":0.0049,"2.4.6-p15":0.0044,"2.4.6-p2":0.0023,"2.4.6-p3":0.0033,"2.4.6-p4":0.0039,"2.4.6-p5":0.0049,"2.4.6-p6":0.0044,"2.4.6-p7":0.0036,"2.4.6-p8":0.0037,"2.4.6-p9":0.0026,"2.4.7":0.0873,"2.4.7-p1":0.0044,"2.4.7-p10":0.0036,"2.4.7-p2":0.0023,"2.4.7-p3":0.007,"2.4.7-p4":0.0149,"2.4.7-p5":0.5173,"2.4.7-p6":0.0225,"2.4.7-p7":0.0141,"2.4.7-p8":0.0104,"2.4.7-p9":0.0106,"2.4.8":0.0051,"2.4.8-p1":0.0065,"2.4.8-p2":0.0063,"2.4.8-p3":0.0082,"2.4.8-p4":0.007,"2.4.8-p5":0.0064,"2.4.9":0.0041,"unspecified":0.0037},"confidence":0.2761},"backportWorthy":{"score":1.8207,"probabilities":{"0":0.031,"1":0.1173,"2":0.8517},"confidence":0.6101}},"curated":{"title":"Fixes Catalog Products List widget failing on malformed UTF-8 in query string","description":"When the query string contains a malformed UTF-8 sequence, such as a truncated fbclid or utm_source parameter, the Catalog Products List widget fails to render and a CRITICAL entry is logged, because the cache key serializer throws an exception. ProductsList::getCacheKeyInfo() now scrubs invalid UTF-8 byte sequences from the request params with mb_scrub before serialization.","categories":["Content"],"author":"claude-code/opus-5.5","date":"2026-10-06","reviewedBy":null},"tests":{"2.4.8-p5":{"before":"not-runnable","after":"error","adapted":false,"runAt":"2026-10-06T09:20:24.050Z","releaseCommit":"870a22c63d9d9b68fa3297962e2d5d5841115814","suites":{"unit":{"before":"not-runnable","after":"error","runAt":"2026-10-06T09:20:24.050Z"}}},"2.4.9":{"before":"not-runnable","after":"pass","adapted":false,"runAt":"2026-10-06T09:20:24.343Z","releaseCommit":"755e34dd689021c5165db9d35ecff74f7dc51527","suites":{"unit":{"before":"not-runnable","after":"pass","runAt":"2026-10-06T09:20:24.343Z"}}},"2.4.7-p10":{"before":"not-runnable","after":"error","adapted":false,"runAt":"2026-10-06T09:29:31.754Z","releaseCommit":"72561bf80652f57cc642a03e2c9a51d74a285b14","suites":{"unit":{"before":"not-runnable","after":"error","runAt":"2026-10-06T09:29:31.754Z"}}}}},"_documentation":"https://magento.watch/api","_description":"Upstream fix magento2-40825 details"}