Shopify/liquid · error · Liquid::FileSystemError
Illegal template name '#
Error message
Illegal template name '#{template_path}' What it means
LocalFileSystem#full_path raises Liquid::FileSystemError when the template name fails the allowed pattern (must start with a non-dot, non-slash character and contain only alphanumerics, underscores, and slashes). This rejects names that could escape the template root or reference odd paths.
Solutions
- Sanitize the template name: strip extensions and disallowed characters before it reaches the include tag.
- Use only [a-zA-Z0-9_/] characters (no dots, hyphens, or leading slash) in template names.
- Never build include names from raw user input; map user choices to a whitelist of template names.
- If you need different naming, subclass LocalFileSystem and override full_path with your own validation.
Example fix
// before
{% include '{{ user_input }}' %} # user_input = "blog/post.html"
// after
{% assign slug = user_input | split: '.' | first %}
{% include slug %} # "blog/post" — safe characters only Defensive patterns
Strategy: validation
Validate before calling
TEMPLATE_NAME_RE = /\A[a-zA-Z0-9_]+(?:\/[a-zA-Z0-9_]+)*\z/ def safe_template_name?(name) TEMPLATE_NAME_RE.match?(name.to_s) end
Type guard
def sanitize_template_name(input) name = input.to_s.sub(/\.[^.]*\z/, '').gsub(/[^a-zA-Z0-9_\/]/, '') TEMPLATE_NAME_RE.match?(name) ? name : nil end
Try / catch
begin
tpl.render(ctx)
rescue Liquid::FileSystemError => e
raise unless e.message.start_with?('Illegal template name')
render_error_page('Invalid template reference')
end Prevention
- Never derive include names directly from user input or URLs.
- Whitelist allowed template names instead of sanitizing arbitrary input.
- Strip file extensions from dynamic names before including.
- Keep names to alphanumerics, underscores, and slashes only.
When it happens
Trigger: Passing a template name containing '.', '..', leading '/', spaces, hyphens, or other disallowed characters to {% include %}/{% render %}, e.g. {% include '../secret' %} or {% include 'my-file' %}.
Common situations: Dynamic include names built from user data or URLs (which contain dots/hyphens); attempting directory traversal via '../'; using file names with extensions inside the tag (the extension comes from the pattern instead).
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Illegal template path '#
- This liquid context does not allow includes.
- No such template '#
- Template.file_system=
- Nesting too deep
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/bb9b1ea5e23f6116.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/file_system.rb:62
# file_system.full_path("index") # => "/some/path/index.html"
#
class LocalFileSystem
attr_accessor :root
def initialize(root, pattern = "_%s.liquid")
@root = root
@pattern = pattern
end
def read_template_file(template_path)
full_path = full_path(template_path)
raise FileSystemError, "No such template '#{template_path}'" unless File.exist?(full_path)
File.read(full_path)
end
def full_path(template_path)
raise FileSystemError, "Illegal template name '#{template_path}'" unless %r{\A[^./][a-zA-Z0-9_/]+\z}.match?(template_path)
full_path = if template_path.include?('/')
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
else
File.join(root, @pattern % template_path)
end
raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path).start_with?(File.expand_path(root))
full_path
end
end
end
View on GitHub (pinned to 807d45a6b3)