Shopify/liquid · error · Liquid::ArgumentError
invalid byte sequence in #
Error message
invalid byte sequence in #{result.encoding} What it means
The url_decode Liquid filter raises Liquid::ArgumentError when CGI.unescape produces a string whose bytes are invalid in the result's encoding. This happens when percent-decoding yields bytes that don't form valid characters (e.g. invalid UTF-8 sequences).
Solutions
- Fix the input so percent escapes represent valid UTF-8 sequences (re-encode the source as UTF-8 before percent-encoding)
- Sanitize/strip invalid percent sequences from the input before applying the filter
- If binary data must round-trip, use base64 encoding instead of url encoding
Example fix
<!-- before -->
{{ '%FF' | url_decode }}
<!-- after -->
{{ '%C3%BF' | url_decode }} Defensive patterns
Strategy: validation
Validate before calling
def url_decodable?(s) decoded = CGI.unescape(s.to_s) decoded.valid_encoding? end
Type guard
def valid_encoding_string?(v) v.is_a?(String) && CGI.unescape(v).valid_encoding? end
Try / catch
begin
output = Liquid::Template.parse(tpl).render(assigns)
rescue Liquid::ArgumentError => e
raise unless e.message.start_with?('invalid byte sequence')
# sanitize input and retry or use fallback
end Prevention
- Percent-encode UTF-8 sources correctly before decoding
- Reject suspicious encoded input at ingestion
- Prefer base64 for binary round-trips
- Test filters with edge-case encodings
When it happens
Trigger: Calling {{ '%FF%FE' | url_decode }} or similar with percent escapes that decode to bytes invalid for the string encoding (commonly invalid UTF-8).
Common situations: Decoding URL-encoded binary data that isn't UTF-8; double-encoded or corrupted query strings from external systems; legacy percent-encodings of non-UTF-8 charsets (e.g. Latin-1 bytes).
Related errors
- Invalid byte sequence in #
- invalid base64 provided to base64_decode
- invalid base64 provided to base64_url_safe_decode
- errors.syntax.invalid_template_encoding
- Invalid byte sequence in #
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/9e8db4840abf1799.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/standardfilters.rb:150
# @liquid_syntax string | url_encode
# @liquid_return [string]
def url_encode(input)
CGI.escape(Utils.to_s(input)) unless input.nil?
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category string
# @liquid_summary
# Decodes any [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding) characters
# in a string.
# @liquid_syntax string | url_decode
# @liquid_return [string]
def url_decode(input)
return if input.nil?
result = CGI.unescape(Utils.to_s(input))
raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
result
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category string
# @liquid_summary
# Encodes a string to [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
# @liquid_syntax string | base64_encode
# @liquid_return [string]
def base64_encode(input)
Base64.strict_encode64(Utils.to_s(input))
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category stringView on GitHub (pinned to 807d45a6b3)