[SalesForce] Intermittant error: Too many components for aura

I am getting error Too many components for aura://ComponentController.getComponent in my Lightning app.

I've seen the related question here:

Lightning/Aura Components: Too many components for aura

But I don't have more than 10,000 components in my app, or at least I don't believe I do. Also, the error only occurs intermittently.

I can make a particular server side call that gets a list of data, set the attribute for that list and let the rerender happen. Sometimes it will render fine, sometimes loading the same data the error will happen.

Also, so far the issue is only happening on one of the three Salesforce orgs I'm testing on.

Is there something I could be doing that is somehow leaking components ?

Is there some way I can trace how many component instances there are at any one time ?

What counts as a component within the 10,000 limit ? Is it just aura:component items as defined in our own .cmp files or do things like aura:iteration and aura:if within our components count towards the limit ?

Update:

The component that the problem occurs in renders a table that displays office hours for contacts (with 15 minute granularity). Within the component, while iterating over a list that contains the office hours for each day for a contact does:

<aura:iteration items="{!contactWrapper.Days}" var="day">
        <aura:iteration items="{!day.Hours}" var="hourData">
          <td scope="col" class="officeDivider">
          </td>          
          <td class="{!hourData[0]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!hourData[1]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!hourData[2]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!hourData[3]}">
            <span class="slds-truncate"></span>
          </td>
        </aura:iteration>
</aura:iteration>

The office hours cover the period 6am-10pm, over 5 days, so the internal bit of those nested aura:iteration gets rendered 75 times for each contact in the list.

If I comment out that inner aura:iteration the error goes away, but of course the data isn't rendered. I thought I'd be clever and upwrap the inner iteration. So I replaced it with:

          <td scope="col" class="officeDivider">
          </td>          
          <td class="{!day.Hours[0][0]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!day.Hours[0][1]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!day.Hours[0][2]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!day.Hours[0][3]}">
            <span class="slds-truncate"></span>
          </td>

all the way through to (one chunk like this for each hour):

          <td scope="col" class="officeDivider">
          </td>          
          <td class="{!day.Hours[15][0]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!day.Hours[15][1]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!day.Hours[15][2]}">
            <span class="slds-truncate"></span>
          </td>
          <td class="{!day.Hours[15][3]}">
            <span class="slds-truncate"></span>
          </td>

So I've removed those 75 instances of that inner aura:iteration completely. Problem solved, right ?

No, the error still occurs. If I comment out most of the unrolled bits, so I just show a couple of hours, the error goes away.

Does that mean that the expressions in the class attributes are somehow counting towards the limit ? (I can't see how they could be, is if they were I'd be over the limit all the time loading this data)

Best Answer

I have now solved this issue in my app. The root cause was that I am using dynamically created components and I wasn't explicitly declaring them as dependencies in their parent component. So I had code like this:

$A.createComponent(
    "c:officeHoursTable",
    {
        "contactList": component.get("v.contactOfficeHours")
    },
    function(newList) {
        if (component.isValid()) {
            var cell = component.find("officeHoursPlaceholder");
            cell.set("v.body", newList);
        }
    }
);

My c:officeHoursTable was not declared as dependency, so createComponent was going to the server to create the component. It was on the server that in some cases I was hitting the limit on the number of components that can be created.

I had seen the "10,000 components" limit talked about, but I hadn't seen the detail on it as documented by Salesforce:

There’s no limit in component creation on the client side. You can create up to 10,000 components in one server request. If you hit this limit, ensure that you’re creating components on the client side in markup or in JavaScript using $A.createComponent() or $A.createComponents(). To avoid a trip to the server for component creation in JavaScript code, add an <aura:dependency> tag for the component in the markup to explicitly tell the framework about the dependency.

So there is no limit on the client side, but there is a limit on the server side.

The fix

To fix the problem, I just added a dependancy definiton to the component that is dynamically creating my officeHoursTable component:

<aura:dependency resource="markup://c:officeHoursTable" />

That stops Aura ever going to the server to create the officeHoursTable component and the problem goes away.

I have a couple of questions that I still don't really definitively know the answer to:

Why was I hitting the limit ?

I still don't know why I was hitting the limit. With my understanding of what I component is, when I was rendering data for 40 contacts my officeHoursTable component was creating around 1,000 components. That is an order of magnitude lower than the stated limit.

My component doesn't nest any of my other components, it uses: aura:if, aura:iteration, and ui:outputText.

My best guess is that my understanding of what counts as a component is wrong. I'm guessing that every expression in an HTML attribute counts against the component limit.

Looking at the Aura source it looks to me like expressions are indeed aura:expression components, which in turn instantiate aura:text components to render their output. Which probably makes hitting 10,000 components not too hard.

In that case, then my 40 record test case would hit the limit every time.

Which brings me to the next question:

Why was it intermittent ?

The issue appeared very much intermittent, sometimes my 40 record test case would render without problem.

My best guess is that when the 40 record test case was working, it was because I had already loaded the officeHoursTable component with a smaller number of records that didn't trigger the limit. Once the component has been created on the server successfully once the framework doesn't go back to the server when asked to create another instance of the component.

And the last outstanding question:

Why has it started happening now ?

As best as I can tell this wasn't happening with my same code last week, this component creation error only appeared to start happening recently. I'm guessing an update to the framework was rolled out that somehow changed how the limit is applied.