{"record":{"id":"850921d1f8ae97a9","repo":"Shopify/liquid","slug":"unsafe-parse-expression-cannot-be-used-in-strict2","errorCode":null,"errorMessage":"unsafe parse_expression cannot be used in strict2 mode","messagePattern":"unsafe parse_expression cannot be used in strict2 mode","errorType":"exception","errorClass":"Liquid::InternalError","httpStatus":null,"severity":"error","filePath":"lib/liquid/parse_context.rb","lineNumber":66,"sourceCode":"        line_number: start_line_number,\n        for_liquid_tag: for_liquid_tag,\n      )\n    end\n\n    def safe_parse_expression(parser)\n      Expression.safe_parse(parser, @string_scanner, @expression_cache)\n    end\n\n    def parse_expression(markup, safe: false)\n      if !safe && @error_mode == :strict2\n        # parse_expression is a widely used API. To maintain backward\n        # compatibility while raising awareness about strict2 parser standards,\n        # the safe flag supports API users make a deliberate decision.\n        #\n        # In strict2 mode, markup MUST come from a string returned by the parser\n        # (e.g., parser.expression). We're not calling the parser here to\n        # prevent redundant parser overhead.\n        raise Liquid::InternalError, \"unsafe parse_expression cannot be used in strict2 mode\"\n      end\n\n      Expression.parse(markup, @string_scanner, @expression_cache)\n    end\n\n    def partial=(value)\n      @partial = value\n      @options = value ? partial_options : @template_options\n\n      @error_mode = @options[:error_mode] || @environment.error_mode\n    end\n\n    def partial_options\n      @partial_options ||= begin\n        dont_pass = @template_options[:include_options_blacklist]\n        if dont_pass == true\n          { locale: locale }\n        elsif dont_pass.is_a?(Array)","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/Shopify/liquid/blob/807d45a6b3d4568e64e86b375e3702df2c7c860c/lib/liquid/parse_context.rb#L48-L84","documentation":"Liquid's parse_context raises Liquid::InternalError when ParseExpression is called with unsafe markup while the parser is in strict2 mode. In strict2, all expression markup must come from the parser itself (e.g. parser.expression) to guarantee the scanner state stays consistent. The safe flag lets API users opt in deliberately.","triggerScenarios":"Calling parse_expression (or ParseContext#parse_expression) with markup that was not produced by the parser while @strict_parse / strict2 mode is enabled, e.g. custom tags handing raw string markup into expression parsing.","commonSituations":"Custom tag implementations migrated to newer Shopify/Liquid versions with strict parsing enabled; embedding engines (like Shopify themes tooling) that force strict2; reusing legacy tag code that passed ad-hoc markup strings.","solutions":["Extract expression markup via parser.expression (or parser or parser expression helpers) instead of parse_expression with raw strings","Pass the safe flag (parse_expression with safe: true equivalent) after auditing that the markup comes from trusted parser output","Disable strict2 mode if you must keep legacy behavior (not recommended)"],"exampleFix":"// before\ncontext.parse_expression(raw_markup)\n// after\nparser = Liquid::Parser.new(raw_markup)\nexpr = context.parse_expression(parser.expression)","handlingStrategy":"try-catch","validationCode":"raise Liquid::InternalError unless context.strict_parse_compatible?(markup) # ensure markup originates from parser.expression before calling parse_expression","typeGuard":"def parser_safe?(markup)\n  markup.is_a?(String) && markup.frozen? # only parser-produced strings qualify in strict2\nend","tryCatchPattern":"begin\n  context.parse_expression(markup)\nrescue Liquid::InternalError => e\n  # fall back to parser.expression extraction\n  parser = Liquid::Parser.new(markup.to_s)\n  context.parse_expression(parser.expression)\nend","preventionTips":["Always source expression markup from parser.expression in custom tags","Audit custom tags when enabling strict2 mode","Add template-parsing tests covering every custom tag"],"tags":["liquid","template-engine","parser","strict-mode"],"backgroundTag":"unsupported-operation","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"}