Skip to content

Handlebars throws IndexOutOfRangeException #395

@DavidBoike

Description

@DavidBoike

Describe the bug

In certain situations, Handlebars will throw an IndexOutOfRangeException. There may be more use cases, but I have isolated one in which the failure is dependent upon the existence of an unused partial template with fairly innocuous contents.

HandlebarsDotNet.HandlebarsRuntimeException : Runtime error while rendering partial 'Navigation', see inner exception for more information
    ---- System.IndexOutOfRangeException : Index was outside the bounds of the array.
  Stack Trace: 
    PartialBinder.InvokePartial(String partialName, BindingContext context, EncodedTextWriter writer, ICompiledHandlebarsConfiguration configuration)
    PartialBinder.InvokePartialWithFallback(String partialName, BindingContext context, EncodedTextWriter writer, ICompiledHandlebarsConfiguration configuration)
    lambda_method(Closure , EncodedTextWriter& , BindingContext )
    <>c__DisplayClass15_0.<Compile>b__0(TextWriter writer, Object context, Object data)
    <>c__DisplayClass16_0.<Compile>b__0(Object context, Object data)
    RenderingWithUnusedPartials.ShouldRender() line 61
    ----- Inner Stack Trace -----
    ArrayIterator`1.Iterate(EncodedTextWriter& writer, BindingContext context, ChainSegment[] blockParamsVariables, Object input, TemplateDelegate template, TemplateDelegate ifEmpty)
    IIterator.Iterate(EncodedTextWriter& writer, BindingContext context, ChainSegment[] blockParamsVariables, Object input, TemplateDelegate template, TemplateDelegate ifEmpty)
    Iterator.Iterate(BindingContext context, EncodedTextWriter writer, ChainSegment[] blockParamsVariables, Object target, TemplateDelegate template, TemplateDelegate ifEmpty)
    lambda_method(Closure , EncodedTextWriter& , BindingContext )
    <>c__DisplayClass15_0.<Compile>b__0(TextWriter writer, Object context, Object data)
    PartialBinder.InvokePartial(String partialName, BindingContext context, EncodedTextWriter writer, ICompiledHandlebarsConfiguration configuration)

Expected behavior:

Should render without throwing.

Test to reproduce

public class RenderingWithUnusedPartial
{
    [Fact]
    public void ShouldRender()
    {
        var handlebars = Handlebars.Create();

        var mainTemplate = @"
{{>Navigation}}
";

        var navPartial = @"
<div>
    {{#each MenuItems}}
    <div>Menu Item: {{Name}}</div>
    {{/each}}
</div>";

        // Remove the {{#if First}} section, and the test will pass
        var unusedPartial = @"
{{#each Results}}
    Result
    {{#if HasSinglePackage}}
        HasSinglePackage
        {{#if First}}
            First
        {{/if}}
    {{/if}}
{{/each}}";

        var navTemplate = handlebars.Compile(mainTemplate);
        Console.WriteLine("Registered template: Navigation");

        using (var reader = new StringReader(navPartial))
        {
            handlebars.RegisterTemplate("Navigation", handlebars.Compile(reader));
            Console.WriteLine("Registered partial: Navigation ");
        }

        // Comment this section out and the test will succeed
        using (var reader = new StringReader(unusedPartial))
        {
            handlebars.RegisterTemplate("Unused", handlebars.Compile(reader));
            Console.WriteLine("Registered partial: Unused ");
        }

        // Attempted with concrete classes, still fails
        var context = new
        {
            MenuItems = new[]
            {
                    new { Name = "Getting Started"}
                }
        };

        var transformed = navTemplate(context).Trim();

        Assert.Equal(@"<div>
    <div>Menu Item: Getting Started</div>
</div>", transformed);
    }
}

Other related info

  • Tested in 2.0.1
  • Tested using netcoreapp3.1 and net5.0 target frameworks

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions