Shopify/liquid · error · Liquid::ArgumentError

invalid base64 provided to base64_url_safe_decode

Error message

invalid base64 provided to base64_url_safe_decode

What it means

The base64_url_safe_decode Liquid filter raises Liquid::ArgumentError when Base64.urlsafe_decode64 cannot decode the input — typically because it contains standard-alphabet characters (+ and /) or is malformed (bad padding/length).

Solutions

  1. Use base64_decode for standard base64 strings containing + or /
  2. Ensure the input uses - and _ alphabet characters with correct padding
  3. Validate the string length and alphabet before decoding

Example fix

<!-- before -->
{{ 'a+b/c==' | base64_url_safe_decode }}
<!-- after -->
{{ 'a-b_c==' | base64_url_safe_decode }}
Defensive patterns

Strategy: validation

Validate before calling

def urlsafe_base64?(s)
  s.is_a?(String) && s.match?(/\A[A-Za-z0-9_-]*={0,2}\z/) && (s.length % 4).zero?
end

Type guard

def urlsafe_alphabet?(v)
  v.is_a?(String) && !v.match?(/[+\/]/)
end

Try / catch

begin
  output = Liquid::Template.parse(tpl).render(assigns)
rescue Liquid::ArgumentError => e
  raise unless e.message.include?('base64_url_safe_decode')
  # retry with base64_decode for standard alphabet input
end

Prevention

When it happens

Trigger: Calling {{ 'a+b/c==' | base64_url_safe_decode }} with standard base64 containing + or /, or a string with invalid length/padding for URL-safe decoding.

Common situations: Feeding standard base64 (from JWT segments or API responses using + /) into the URL-safe filter; truncated tokens; padding mixed with URL-safe unpadded encoding.

Related errors


AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08). Data as JSON: /api/errors/0e7fdc4d42f29c11. Report an issue: GitHub.

Appendix: source

Thrown at lib/liquid/standardfilters.rb:202

    #   Encodes a string to URL-safe [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
    # @liquid_syntax string | base64_url_safe_encode
    # @liquid_return [string]
    def base64_url_safe_encode(input)
      Base64.urlsafe_encode64(Utils.to_s(input))
    end

    # @liquid_public_docs
    # @liquid_type filter
    # @liquid_category string
    # @liquid_summary
    #   Decodes a string in URL-safe [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
    # @liquid_syntax string | base64_url_safe_decode
    # @liquid_return [string]
    def base64_url_safe_decode(input)
      input = Utils.to_s(input)
      StandardFilters.try_coerce_encoding(Base64.urlsafe_decode64(input), encoding: input.encoding)
    rescue ::ArgumentError
      raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
    end

    # @liquid_public_docs
    # @liquid_type filter
    # @liquid_category string
    # @liquid_summary
    #   Returns a substring or series of array items, starting at a given 0-based index.
    # @liquid_description
    #   By default, the substring has a length of one character, and the array series has one array item. However, you can
    #   provide a second parameter to specify the number of characters or array items.
    # @liquid_syntax string | slice
    # @liquid_return [string]
    def slice(input, offset, length = nil)
      offset = Utils.to_integer(offset)
      length = length ? Utils.to_integer(length) : 1

      begin
        if input.is_a?(Array)

View on GitHub (pinned to 807d45a6b3)