{"record":{"id":"d742be60d3a80f2e","repo":"Shopify/liquid","slug":"undefined-variable-key","errorCode":null,"errorMessage":"undefined variable #{key}","messagePattern":"undefined variable #(.+?)","errorType":"exception","errorClass":"Liquid::UndefinedVariable","httpStatus":null,"severity":"error","filePath":"lib/liquid/context.rb","lineNumber":236,"sourceCode":"      end\n\n      # `self` resolves to a SelfDrop (enabling `self['var']` lookups),\n      # but only after the normal environment lookup doesn't find a value.\n      return @self_drop ||= SelfDrop.new(self) if fallback_to_self_drop && variable.nil?\n\n      # update variable's context before invoking #to_liquid\n      variable.context = self if variable.respond_to?(:context=)\n\n      liquid_variable = variable.to_liquid\n\n      liquid_variable.context = self if variable != liquid_variable && liquid_variable.respond_to?(:context=)\n\n      liquid_variable\n    end\n\n    def lookup_and_evaluate(obj, key, raise_on_not_found: true)\n      if @strict_variables && raise_on_not_found && obj.respond_to?(:key?) && !obj.key?(key)\n        raise Liquid::UndefinedVariable, \"undefined variable #{key}\"\n      end\n\n      value = obj[key]\n\n      if value.is_a?(Proc) && obj.respond_to?(:[]=)\n        obj[key] = value.arity == 0 ? value.call : value.call(self)\n      else\n        value\n      end\n    end\n\n    def with_disabled_tags(tag_names)\n      tag_names.each do |name|\n        @disabled_tags[name] = @disabled_tags.fetch(name, 0) + 1\n      end\n      yield\n    ensure\n      tag_names.each do |name|","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/Shopify/liquid/blob/807d45a6b3d4568e64e86b375e3702df2c7c860c/lib/liquid/context.rb#L218-L254","documentation":"Liquid raises Liquid::UndefinedVariable during lookup_and_evaluate when strict_variables mode is on and the requested key does not exist in the object being looked up (and the object responds to key?). This makes missing variables a hard error instead of nil, so typos in variable names fail fast.","triggerScenarios":"Rendering with `Liquid::Context.new(..., strict_variables: true)` (or error_mode strict + strict_variables) while the template references a variable never assigned; variables present only in a different environment/scope than the one searched; passing raise_on_not_found: true lookups for optional keys.","commonSituations":"Teams enabling strict_variables to catch typos, then hitting it for legitimately optional variables; renames of assigns not propagated to all templates; partials expecting variables the caller never passes; tests with incomplete fixtures.","solutions":["Define/assign the missing variable before use: `{% assign key = ... %}` or pass it in the render assigns hash.","Pass the variable via `Template#render('key' => value)` or Environment data so lookups succeed.","For optional variables, use `raise_on_not_found: false` in custom lookups or guard with `{% if key %}` — note strict mode still treats plain nil as error unless handled.","If strict_variables is too aggressive for a template, render that template with strict_variables: false."],"exampleFix":"// before\nLiquid::Template.parse(\"{{ user.name }}\").render  # strict_variables: true, user missing\n// after\ntemplate.render({ \"user\" => { \"name\" => \"Ada\" } }, strict_variables: true)","handlingStrategy":"try-catch","validationCode":"required = %w[user cart]\nmissing = required - assigns.keys\nraise \"missing template vars: #{missing.join(',')}\" unless missing.empty?","typeGuard":"def variable_defined?(assigns, key)\n  assigns.is_a?(Hash) && assigns.key?(key)\nend","tryCatchPattern":"begin\n  html = template.render(assigns, strict_variables: true)\nrescue Liquid::UndefinedVariable => e\n  logger.warn(\"missing template variable: #{e.message}\")\n  html = template.render(assigns, strict_variables: false)\nend","preventionTips":["Enable strict_variables in tests to catch typos early; relax only in render paths with optional vars.","Pass all required variables explicitly via the render assigns hash.","Guard optional variables with {% if %} in templates.","Keep a manifest of variables each partial expects and validate callers against it."],"tags":["liquid","undefined-variable","strict-mode","lookup"],"backgroundTag":"resource-not-found","analyzedSha":"807d45a6b3d4568e64e86b375e3702df2c7c860c","analyzedAt":"2026-09-08T11:31:38.917Z","contentChangedAt":"2026-09-08T11:31:38.917Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}