Shopify/liquid · error · ArgumentError
Expected Hash or Liquid::Context as parameter
Error message
Expected Hash or Liquid::Context as parameter
What it means
Template#render accepts an optional first argument that must be a Hash of assigns, a Liquid::Context, or nil. Any other type (String, Array, integer, etc.) raises ArgumentError with 'Expected Hash or Liquid::Context as parameter'.
Solutions
- Convert the argument to a Hash before rendering: template.render(JSON.parse(json)).
- Pass variables inside a Hash: template.render('key' => value) or use template.assignments/instance assigns.
- If sharing state across renders, construct and pass a Liquid::Context explicitly.
- Pass nothing (or nil) when no outer assigns are needed.
Example fix
// before
template.render('{"user": "bob"}')
// after
template.render(JSON.parse('{"user": "bob"}')) Defensive patterns
Strategy: type-guard
Validate before calling
raise ArgumentError, 'assigns must be a Hash' unless arg.nil? || arg.is_a?(Hash) || arg.is_a?(Liquid::Context)
Type guard
def valid_render_arg?(arg) arg.nil? || arg.is_a?(Hash) || arg.is_a?(Liquid::Context) end
Try / catch
begin
template.render(assigns)
rescue ArgumentError => e
raise e unless e.message.include?('Expected Hash or Liquid::Context')
template.render(assigns.to_h)
end Prevention
- Always pass a Hash or Liquid::Context as the first render argument
- Parse JSON strings before using them as assigns
- Wrap custom assign objects with #to_h at the call site
When it happens
Trigger: Calling template.render('foo'), template.render(assigns_array), or template.render(some_object) where the first argument is neither Hash, Liquid::Context, nor omitted/nil.
Common situations: Passing a JSON string of variables instead of a parsed Hash; passing OpenStruct/dry structs as assigns; refactoring from render! to render while changing argument shapes; tests (e.g. test_internal_error_is_raised_with_template_name) exercising bad arguments.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- e.message (re-raised as Liquid::ArgumentError from…
- cannot sort values of incompatible types
- errors.argument.include
- cannot select the property '#
- invalid integer
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/b27faefa8edb4efa.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/template.rb:163
when Liquid::Context
c = args.shift
if @rethrow_errors
c.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA
end
c
when Liquid::Drop
drop = args.shift
c = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits, {}, @environment)
drop.context = c if drop.respond_to?(:context=)
c
when Hash
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits, {}, @environment)
when nil
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits, {}, @environment)
else
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
end
output = nil
case args.last
when Hash
options = args.pop
output = options[:output] if options[:output]
static_registers = context.registers.static
options[:registers]&.each do |key, register|
static_registers[key] = register
end
apply_options_to_context(context, options)
when Module, Array
context.add_filters(args.pop)
endView on GitHub (pinned to 807d45a6b3)