Repository navigation
fix(base64_decode): throw on invalid input in every build - #971
josefguenther wants to merge 3 commits into
Conversation
The two builds disagreed on input that isn't valid Base64. The node build decodes with Buffer, which skips characters outside the alphabet, so ordinary text such as "hello" or "[object Object]" decoded to garbage bytes. The browser builds decode with atob, which throws, so the same input failed the whole render. base64_decode now checks the input before decoding, in the filter shared by both builds: exactly what atob accepts (the standard alphabet, optional padding and whitespace) decodes as before, and anything else renders an empty string. Valid input is decoded the same way by both builds. Fixes harttle#965 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Sorry for the late response. RenderError is expected for invalid input, as it is consistent with Shopify/liquid, FYI: this is what I get from the Ruby version: What makes LiquidJS more consistent is to throw same errors for both browser and Node.js. But we also want to avoid too complicated or slow implementation as it's only an edge case. Otherwise I'd rather document it as a "difference from Shopify/liquid". |
Shopify/Liquid's default render writes an error message in place of the filter's output and renders the rest of the page; only render! raises. "Raises an error" read as failing the render. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for running these through Ruby. Those "Liquid error: …" strings are what makes me think throwing doesn't match Shopify here. Shopify's default LiquidJS fails the whole render on any error ( So I'd suggest keeping the render going, as Shopify does: an empty string here, U+FFFD for invalid UTF-8 in #970. The fully faithful version would be Shopify's model, where a filter error is kept to its own tag and reported, but that changes how every render error behaves, so it seemed beyond these PRs and maybe a better fit for v11. Happy to open an issue for that if it interests you. |
|
By the way, I tested and Shopify reports an error for bad data in about a dozen filters ( |
|
Thanks for the clarification.
I see there can be many differences still. The principle would be: if it doesn't require a lot of complexity, we should align with Shopify; if there'd be a breaking change, we do it in v11 by adding the issue there; if it's not convenient for JS to implement, we document in the differences section. |
Invalid input rendered an empty string. It now throws "invalid base64 provided to base64_decode", the message Shopify/Liquid uses, from the check both builds share, so the node and browser builds fail the same way on the same input. Padding stays optional and whitespace ignored, as both builds accept today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Reworked: both builds now throw Shopify's |
{{ "hello" | base64_decode }}On master the node build renders garbage bytes (
��e), and the browser builds throwatob's own error, whose message depends on the input and the runtime. Shopify/Liquid raisesinvalid base64 provided to base64_decode. This throws that error from a check both builds share, before decoding.{{ v | base64_decode }}:v"YWJj"abcabcabc"YWJjZA"(unpadded)abcdabcdabcd"YW Jj"(whitespace)abcabcabc"hello"��e"YWJj!!"abc"-_-_"(URL-safe)���5The check accepts exactly what
atobaccepts, so unpadded and whitespace-separated input still decodes in both builds. Shopify rejects those two as well, but rejecting them here would break input that works today.The tests cover the node build in
test/integration/filters/base64.spec.tsand the browser bundle intest/e2e/browser.spec.ts.npm run build,npm test(1676 tests) andnpm run lintpass on Node 24.11.1.Fixes #965
Written with AI assistance (Claude Code); I have reviewed the change.