aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Weird Blazor WASM bug: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Arg_IndexOutOfRangeException

Open aditya119 opened this issue 1 year ago • 3 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

I have a simple page to manipulate access of an employee in a Blazor WASM application:

@page "/Admin/AccessControl"
@attribute [Authorize(Roles = "Admin_ConfigAppUserGroups")]
@using SharedLib.Models
@inject IAdminClient _admin
@inject ISystemClient _system
@inject IToastService _toast

<EditForm Model="newAppUserGroup" OnSubmit="HandleSubmit">
    <fieldset class="form-group" disabled="@isFormDisabled">
        <label class="font-weight-bold" for="users">User</label>
        <select class="form-control" id="users" @onchange="HandleSelectUser"
                value="@newAppUserGroup.UserId.ToString()">
            @if (employees is not null)
            {
                foreach (var employee in employees)
                {
                    <option value="@employee.EmployeeId.ToString()">@employee.FullnameAndCode</option>
                }
            }
        </select>
    </fieldset>
    <fieldset class="form-group" disabled="@isFormDisabled">
        <label class="font-weight-bold" for="applications">Application</label>
        <select class="form-control"
                value="@newAppUserGroup.ApplicationId.ToString()"
                @onchange="HandleSelectApplication"
                id="applications"
                required>
            @if (applications is not null)
            {
                foreach (var app in applications)
                {
                    <option value="@app.ApplicationId.ToString()">@app.ApplicationName</option>
                }
            }
        </select>
    </fieldset>
    <fieldset class="form-group" disabled="@isFormDisabled">
        <label class="font-weight-bold" for="appGroups">AppGroups</label>
        <InputSelectNumber class="form-control" id="appGroups"
                           @bind-Value="newAppUserGroup.AppGroupId">
            <option value="0">-- No access --</option>
            @if (appGroups is not null)
            {
                foreach (var appGroup in appGroups)
                {
                    <option value="@appGroup.AppGroupId">@appGroup.GroupName</option>
                }
            }
        </InputSelectNumber>
    </fieldset>
    <input class="btn btn-primary" type="submit" value="Submit" disabled="@isFormDisabled" />
</EditForm>

@code {
    private bool isFormDisabled;
    private AppUserGroupModel newAppUserGroup = new();
    private IEnumerable<EmployeeListItemModel> employees;
    private IEnumerable<ApplicationModel> applications;
    private IEnumerable<AppGroupListItemModel> appGroups;

    protected override async Task OnInitializedAsync()
    {
        isFormDisabled = true;

        await LoadInitialData();

        isFormDisabled = false;
    }

    private async Task LoadAppGroups()
    {
        appGroups = await _admin.AppGroups_GetAllAsync(newAppUserGroup.ApplicationId);

        var desiredGroup = (await _admin.AppUserGroups_GetAllAsync(newAppUserGroup.UserId)).FirstOrDefault(g => g.UserId == newAppUserGroup.UserId && g.ApplicationId == newAppUserGroup.ApplicationId);
        newAppUserGroup.AppGroupId = desiredGroup is null ? 0 : desiredGroup.AppGroupId;
    }

    private async Task LoadInitialData()
    {
        var employeesTask = _admin.Employees_GetAllAsync(Systems.Shared.Enums.AdminSchema.EmployeeFilter.All);
        var applicationsTask = _system.Applications_GetAllAsync();

        employees = await employeesTask;
        applications = await applicationsTask;

        newAppUserGroup.UserId = employees.FirstOrDefault().EmployeeId;
        newAppUserGroup.ApplicationId = applications.FirstOrDefault().ApplicationId;

        await LoadAppGroups();
    }

    private async Task HandleSelectUser(ChangeEventArgs args)
    {
        isFormDisabled = true;

        newAppUserGroup.UserId = int.Parse(args.Value.ToString());

        await LoadAppGroups();

        isFormDisabled = false;
    }

    private async Task HandleSelectApplication(ChangeEventArgs args)
    {
        isFormDisabled = true;

        newAppUserGroup.ApplicationId = int.Parse(args.Value.ToString());

        await LoadAppGroups();

        isFormDisabled = false;
    }

    private async Task HandleSubmit()
    {
        isFormDisabled = true;

        // handle submit logic here

        isFormDisabled = false;
    }
}

It has been working fine for almost a year.

The IAdminClient and ISystemsClient are abstractions for HTTP requests.

The implementations are as below:

    public Task<IEnumerable<ApplicationModel>> Applications_GetAllAsync()
    {
        return _http.GetFromJsonAsync<IEnumerable<ApplicationModel>>("api/Applications");
    }
    public Task<IEnumerable<EmployeeListItemModel>> Employees_GetAllAsync(EmployeeFilter filter)
    {
        return _http.GetFromJsonAsync<IEnumerable<EmployeeListItemModel>>($"api/Employees?filter={(int)filter}");
    }
    public Task<IEnumerable<AppGroupListItemModel>> AppGroups_GetAllAsync(int applicationId)
    {
        return _http.GetFromJsonAsync<IEnumerable<AppGroupListItemModel>>($"api/AppGroups?applicationId={applicationId}");
    }
    public Task<IEnumerable<AppUserGroupModel>> AppUserGroups_GetAllAsync(int userId)
    {
        return _http.GetFromJsonAsync<IEnumerable<AppUserGroupModel>>($"api/AppUserGroups?userId={userId}");
    }

Now, the page does not load, giving error:

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Arg_IndexOutOfRangeException
System.IndexOutOfRangeException: Arg_IndexOutOfRangeException
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendAttributeDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer , RenderBatchBuilder , Int32 , ArrayRange`1 , ArrayRange`1 )
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder , RenderFragment , Exception& )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

Expected Behavior

The expected behaviour is that page should load properly.

It has been working as expected for the last 10 months.

The number of 'Applications' and 'AppGroups' has remained the same over this period. Recently, the number of employees increased to 156 and we started facing this issue.

I manually updated logic in API to return 155, 157, and 158 employees and the page works as expected. But it seems that there is some issue when the count is 156.

Steps To Reproduce

The bug is reproducible as the page does not load when Employees_GetAllAsync(EmployeeFilter filter) returns 156 items.

But I cannot isolate the issue, as the there are other pages as well having similar Employee dropdown and they are working fine.

Exceptions (if any)

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Arg_IndexOutOfRangeException
System.IndexOutOfRangeException: Arg_IndexOutOfRangeException
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendAttributeDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForFramesWithSameSequence(DiffContext& , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 )
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer , RenderBatchBuilder , Int32 , ArrayRange`1 , ArrayRange`1 )
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder , RenderFragment , Exception& )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry )
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

.NET Version

6.0

Anything else?

No response

aditya119 avatar Oct 14 '22 13:10 aditya119

@aditya119 thanks for contacting us.

I don't see anything immediately wrong with the app. Could you debug the app and break on first-chance exceptions to see if there is an exception being thrown that it's not surfacing?

If this does not yield any result (the issue appears to originate from Blazor in the first case). Could you file an issue through the Visual Studio report a problem dialog Report a problem with Visual Studio - Visual Studio (Windows) | Microsoft Docs and include a dump captured at the time the exception is thrown using dotnet dump? (Debug the app, break on the exception, capture the memory dump)

javiercn avatar Oct 14 '22 14:10 javiercn

Hi @aditya119. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

ghost avatar Oct 14 '22 14:10 ghost

@javiercn An issue has reported using Visual Studio. Reference

The dotnet dump collected from the debug process has been attached to the issue.

The debug did not raise any other exception except the one already mentioned. Breaking the exception takes us to the _vs/browserLink JS file.

I have also added the lower section of the exception displayed in browser's debugger console:

<html>
<body>
<!--StartFragment-->

window.Module.s.printErr | @ | blazor.webassembly.js:1
-- | -- | --
  | Fe._internal.dotNetCriticalError | @ | blazor.webassembly.js:1
  | St | @ | blazor.webassembly.js:1
  | _mono_wasm_invoke_js_blazor | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0fb
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed_BINDINGS_SetTaskSourceResult | @ | managed_BINDINGS_SetTaskSourceResult:17
  | (anonymous) | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | Promise.then (async) |   |  
  | _wrap_js_thenable_as_task | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _js_to_mono_obj | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _mono_wasm_invoke_js_with_args | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed_BINDINGS_SetTaskSourceResult | @ | managed_BINDINGS_SetTaskSourceResult:17
  | (anonymous) | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | Promise.then (async) |   |  
  | _wrap_js_thenable_as_task | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _js_to_mono_obj | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _mono_wasm_invoke_js_with_args | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed_BINDINGS_SetTaskSourceResult | @ | managed_BINDINGS_SetTaskSourceResult:17
  | (anonymous) | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | Promise.then (async) |   |  
  | _wrap_js_thenable_as_task | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _js_to_mono_obj | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _mono_wasm_invoke_js_with_args | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed_BINDINGS_SetTaskSourceResult | @ | managed_BINDINGS_SetTaskSourceResult:17
  | (anonymous) | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | Promise.then (async) |   |  
  | _wrap_js_thenable_as_task | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _js_to_mono_obj | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _mono_wasm_invoke_js_with_args | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed_BINDINGS_SetTaskSourceResult | @ | managed_BINDINGS_SetTaskSourceResult:17
  | (anonymous) | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | Promise.then (async) |   |  
  | _wrap_js_thenable_as_task | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _js_to_mono_obj | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _mono_wasm_invoke_js_with_args | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed_BINDINGS_SetTaskSourceResult | @ | managed_BINDINGS_SetTaskSourceResult:17
  | (anonymous) | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | Promise.then (async) |   |  
  | _wrap_js_thenable_as_task | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _js_to_mono_obj | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | _mono_wasm_invoke_js_with_args | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1613 | @ | 00970c26:0x6f8a7
  | $func966 | @ | 00970c26:0x502f8
  | $func219 | @ | 00970c26:0x1a0b4
  | $func167 | @ | 00970c26:0xcac9
  | $func166 | @ | 00970c26:0xb9dc
  | $func2810 | @ | 00970c26:0xabb22
  | $func1615 | @ | 00970c26:0x6f935
  | $func1619 | @ | 00970c26:0x6ffa2
  | $mono_wasm_invoke_method | @ | 00970c26:0x969b
  | Module._mono_wasm_invoke_method | @ | dotnet.6.0.4.tmvd13mk96.js:1
  | managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet | @ | managed__Microsoft_A…eginInvokeDotNet:19
  | beginInvokeDotNetFromJS | @ | blazor.webassembly.js:1
  | b | @ | blazor.webassembly.js:1
  | e.invokeMethodAsync | @ | blazor.webassembly.js:1
  | (anonymous) | @ | blazor.webassembly.js:1
  | ve | @ | blazor.webassembly.js:1
  | we | @ | blazor.webassembly.js:1
  | (anonymous) | @ | blazor.webassembly.js:1
  | (anonymous) | @ | blazor.webassembly.js:1
  | onGlobalEvent

<!--EndFragment-->
</body>
</html>

aditya119 avatar Oct 15 '22 15:10 aditya119

@aditya119 can you disable (if you have enabled them) browserlink and hotreload?

javiercn avatar Oct 16 '22 18:10 javiercn

Hi @aditya119. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

ghost avatar Oct 17 '22 14:10 ghost

@javiercn Have added new dump with browser link and hot reload disabled.

VS issue link

aditya119 avatar Oct 18 '22 09:10 aditya119

Hi @javiercn Can you please share some details on the issue, is it something specific to having multiples of 156 items in dropdown? Is there some workaround available? Thanks.

aditya119 avatar Oct 20 '22 03:10 aditya119

@danroth27 @javiercn Is there any update on this?

aditya119 avatar Nov 03 '22 12:11 aditya119

Thanks for provided the memory dump, @aditya119.

It may take us approximately a month to get to this investigation. This issue is assigned to the 8.0-preview1 milestone, which is the first milestone for that upcoming .NET 8 release. Right now, the team is focused on some infrastructure-related work, addressing technical debt that we've accumulated over time. Only after completing this phase, we will be able to switch to addressing 8.0 issues. Hope this helps with your planning.

mkArtakMSFT avatar Nov 03 '22 16:11 mkArtakMSFT

Thanks for the update @mkArtakMSFT. Since this is impacting a production system, it would be great if you can provide some details on this issue. Is it something specific to having 156 elements in the select dropdown? Is there a workaround/update that can be made in code so that this exception is avoided temporarily?

aditya119 avatar Nov 03 '22 16:11 aditya119

~~I looked at the Dump and it does not contain any circuit. The dump needs to be captured at the time the exception is happening. Otherwise, we are not able to infer what might be going on.~~

Nevermind, this is targeting Blazor Webassembly. We would need a repro of this on Blazor Server with a dump, otherwise we can't tell what's going on.

javiercn avatar Nov 25 '22 18:11 javiercn

Hi @aditya119. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

ghost avatar Nov 25 '22 18:11 ghost

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. If it is closed, feel free to comment when you are able to provide the additional information and we will re-investigate.

See our Issue Management Policies for more information.

ghost avatar Nov 29 '22 19:11 ghost

@javiercn We just updated our application to .Net 7 and we are no longer facing the issue at 156 employees in the dropdown. The issue can be closed for now. Not sure if the issue will occur again at some other number of items, but we are good for now.

aditya119 avatar Dec 06 '22 11:12 aditya119