FilteredElementIterator exception when working with FilteredElementCollector

FilteredElementIterator exception when working with FilteredElementCollector

sroswurm4GJQU
Advocate Advocate
3,118 Views
12 Replies
Message 1 of 13

FilteredElementIterator exception when working with FilteredElementCollector

sroswurm4GJQU
Advocate
Advocate

Afternoon All,

 

I'm working with Revit 2020.  I was curious to see if there are any known issues where attempting to iterate over a FilteredElementCollector may intermittently generate an exception?  In my case, I'm constructing a FilteredElementCollector that uses an ElementIntersectsSolidFilter and a LogicalAnd containing several BuiltInCategories.

 

Having constructed the collector and applied filters, it seems that any form of iteration has the potential to generate an exception that references the FilteredElementIterator. Here's the basic format I've been using (nothing complicated, as you can see):

 

//Declare collector and apply filter

FilteredElementCollector myCollector = new FilteredElementCollector(doc);

myCollector.WherePasses(myFilter);

 

//Iterate over the collector

foreach(Element myElement in myCollector)

{

          //Do stuff with the passing elements

}

 

Oddly enough, however, I have observed in testing that the same code may alternately error out or execute perfectly in two consecutive tests with no change to the code.  As a result, I do not have a reproducible test case, because I cannot "force" a configuration where it always reliably fails.  I've been through several full-day marathons of testing, debugging, and tweaking the code.  I always finish the day believing I've resolved it and then 3 days later after many successful uses it unexpectedly errors out again with no apparent cause.

 

My first assumption is always that I have an error in my code.  However, the fact that it can fail and then run successfully back to back with 100% identical conditions makes me wonder if there is a bug or instability that is beyond my reach.

 

I've used FilteredElementCollectors extensively for many different purposes from Revit 2017 all the way up to Revit 2020 and have never before observed this behavior.  Any thoughts on this???

0 Likes
Accepted solutions (1)
3,119 Views
12 Replies
Replies (12)
Message 2 of 13

sroswurm4GJQU
Advocate
Advocate

Update:  As a further clarification, the exception type being thrown is "Autodesk.Revit.Exceptions.InternalException" (see attached screenshot).

 

On this topic, the API docs say:

"The exception that is thrown when an issue in the Revit code resulted in an unexpected error."

"Please contact Autodesk Developer Support with the information about what led to this exception."

0 Likes
Message 3 of 13

RPTHOMAS108
Mentor
Mentor

It would be more usual to call .ToElementIds or .ToElements on the collector and then iterate the results of that rather than iterating the collector directly but should not cause an exception.

 

I guess in any case you'll have to give details of how exactly your code forms myFilter in order for it to be tested.

0 Likes
Message 4 of 13

sroswurm4GJQU
Advocate
Advocate

Unfortunately, I've seen the same exception thrown using  .ToElementIds(), .ToElements(), and using foreach().

 

I'm still digging down into the building of the filter itself to see if I made are any errors on that end. 

I'd feel better if it failed every time.  The fact that it only fails intermittently makes it very difficult to trace.

 

I neglected to mention that I have already tried checking that the collector is not null and that is has contents:

 

if(myCollector != null)

{

          if(myCollector.GetElementCount() > 0)

          {

                    //Still causes an InternalException sometimes (but not on every attempt)

                    ICollection<ElementId> myIDsList = myCollector.ToElementIds();

          }

}

Message 5 of 13

Sean_Page
Collaborator
Collaborator

Do you get mixed result in same model on back to back runs? Or does a working model always work? Could it be your categories and the potential for modeled in place elements? I have seen this wreak havoc on what would appear to be a solid FEC.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 6 of 13

jeremytammik
Autodesk
Autodesk

I would very strongly suggest following the good advice of Richard above, supported by Julius Ceasar, Napoleon and Macchiavelli: divide and conquer.

 

You say:

 

  foreach(Element myElement in myCollector)
  {
    //Do stuff with the passing elements
  }

 

Richard and I say:

 

  foreach(Element myElement in myCollector)
  {
    // Do NOT do stuff with the passing elements
    // Just collect their element ids for later
  }

 

Process the elements afterwards, just using the collected element ids.

 

Then you know that all the problems that you create for yourself are your own, and not due to the element collector.

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 7 of 13

sroswurm4GJQU
Advocate
Advocate

Jeremy,

 

I should have been more clear in my description.  There should be nothing in the "//Do stuff" that is causing an internal exception.  The only action inside the loop was to write the ElementId to an ICollection:

 

ICollection<ElementId> myIDsList = new List<ElementId>();

 

//Iterate over the collector

foreach(Element myElement in myCollector)

{

          myIDsList.Add(myElement.Id);

}

 

Unfortunately, there is still a chance of throwing an InternalException even if I completely eliminate the loop and simply use "ToElements()" or "ToElementIds()".

0 Likes
Message 8 of 13

sroswurm4GJQU
Advocate
Advocate

spage,

 

When I say back-to-back success and failure, I mean 100% identical test conditions in the same model, during the same session, even picking on the exact same element twice in a row. 

There is nothing being done during runtime that would change the model and cause a failure on the next run, and there is no pattern to the order.  It can either pass then fail, or fail and then pass.

Message 9 of 13

stever66
Advisor
Advisor

Is this an external application, an external command, or a macro?

 

I'm wondering if something is still remaining from the previous run.   For example, you run it once and it works.  You run it again, but for some reason the Icollection still contains element ID's from the previous run.   It adds the element again, and now you have a collection that contains 2 of the same element ID's.  

 

that was just a thought.  But it might help for troubleshooting to see how many elements wind up in the collection each time, and compare them for two runs - one with an error, and one without.  If you can manage to get that to happen.

0 Likes
Message 10 of 13

sroswurm4GJQU
Advocate
Advocate

This is an external application.  However, the FilteredElementCollector that's causing the error is wrapped inside a class constructor.  So everything should be brand new every time a new instance of the class is constructed.  However, there is a utility method for getting the intersection solid that feeds into the filter which could be an issue.  I'll look at that further and see if I can turn anything up.

0 Likes
Message 11 of 13

thomas
Advocate
Advocate
Accepted solution

I experienced a similar issue a while ago although it involved a solid intersection filter and extraction of solids. 

 

The problem I had was caused by the garbage collector disposing of elements in the collector when it hit the memory threshold which triggers the GC. That's also what made it intermittent and difficult to reproduce. 

 

Assuming your problem is similar, then you'll need to devise a way to optimise the number of elements you collect.

 

Message 12 of 13

sroswurm4GJQU
Advocate
Advocate

Thomas,

 

Your comment was absolute GENIUS!!!!  I had this particular issue on the back burner while working on something else.  All the sudden, it errored out again and this time I jumped to the task manager to look at the memory usage.  After some further testing, I have pretty much convinced myself that the Internal Exception is absolutely correlated to high memory usage on the local machine.

 

This also explains why I struggled to replicate the error and why I could never isolate it when making simplified individual test runs with the smallest building blocks of the program.  In the full implementation, the method that builds and uses a filtered element collector runs many times in a row using many different ElementIntersectsSolidFilter conditions.  So when I would break it down to the tiniest parts and make a single test run, it would always work fine because the limited scope of the test didn't consume enough memory to cause an issue.  In a similar manner, the full program always performs properly when there are no other memory-hogging processes running on the local machine.

 

So now I suppose I'll just break it down and figure out how the memory is being consumed and how to streamline it.  As soon as I can test just a little more to confirm that the Exception is memory-related, I'll come back and mark my question as solved.

 

Thanks again!!

0 Likes
Message 13 of 13

kraftwerk15
Advocate
Advocate

I wanted to add to this thread, as it was the only one I could find regarding an Autodesk.Revit.Exceptions.InternalException when working with a FilteredElementCollector. Looping over a collector with a foreach loop where I declared the FEC to look for a Family object worked correctly for a few times, then suddenly dive in to a InternalException. Like below:

 

FilteredElementCollector collectorUsed = new FilteredElementCollector(doc);
collectorUsed.OfClass(typeof(Autodesk.Revit.DB.Family));
//If value works correctly here irregardless
if (collectorUsed.GetElementCount() > 1)
{
   //bunch of other code here not related
   //starting a transaction
    using(transaction name = new Transaction(doc, "Doing something here"))
    {
        name.Start();
        foreach(Autodesk.Revit.DB.Family r in collectorUsed)
        // this would work for a few then Exception
    }
}

 

I then modified the code to cast to ElementIds and then go fetch the Ids since the Document was already open.

 

FilteredElementCollector collectorUsed = new FilteredElementCollector(doc);
collectorUsed.OfClass(typeof(Autodesk.Revit.DB.Family));
//If value works correctly here irregardless
if (collectorUsed.GetElementCount() > 1)
{
   //bunch of other code here not related
   //starting a transaction
    using(transaction name = new Transaction(doc, "Doing something here"))
    {
        name.Start();
        foreach(ElementId r in collectorUsed.ToElementIds())
        {
            Element elem = doc.GetElement(r);
        }
        // bunches of other code continues.....
    }
}

 Hope that helps someone in the future.

0 Likes