Ken, 332 days later: Today is your lucky day!
A while back, Ken posted this question asking "why are all web parts on a page returned as ErrorWebPart objects when I access them through the SharePoint Object Model?" And by "a while ago", I mean "sometime in the year 2006."
I am proud to say that I have the answer! Ken, today is your lucky day! Hope this answer comes in time!
The scenario
SharePoint migrations are a prime time to do a lot of cleanup. While this cleanup may take many forms, the specific form we are interested in today involves clearing out specific Web Parts from every page in the database.
Assuming our users permit it, we can close, delete, or even add web parts to sites, wholesale. This has the potential to be awesome, and by extension, we can be awesome as well.
Unfortunately, one of the issues you'll encounter with migrations is that (for whatever reason) you may not have all the original web part assemblies available to you on the new server. However, SharePoint expects to be able to use that assembly, and will stubbornly retain all web part references in individual pages on your site. What happens, you may ask, to these web parts already embedded in hundreds (or thousands) of pages on your site? They appear as ErrorWebParts.
It is appropriate to see ErrorWebParts where there is, in fact, an error--that is, when the ErrorWebPart describes a truly legitimate error. However!
The problem
The problem is that we see everything as ErrorWebParts, even things that most definitely are not in any way broken!
Specifically, when writing code to access web parts on a page, we run into a curious problem: some pages return a collection filled only with ErrorWebParts. If you have 20 web parts on a page, you will see 20 ErrorWebParts.
This behavior does not occur 100% of the time, and it's not always the same sites that return ErrorWebParts. Sites that initially return a broken ErrorWebParts collection may work properly the next time around.
So what's the deal?
The answer--well, enough of an answer
I don't know why exactly, but I've narrowed the behavior down to this: errors only occur on pages that have not been visited recently.
Let me state this again for clarity, by example:
If you have visited a web page recently (say, http://moss.example.com/default.aspx), then attempt to query its Web Part collection, all will be well.
If, however, you have not visited a web page recently (say, http://moss.example.com/abandoned_old_site/default.aspx), and attempt to query its Web Part collection, you will see all ErrorWebParts. <- THIS IS THE BUG.
The appalling solution
The way to work around this problem is to guarantee every page has been visited before you access their corresponding Web Part collections. Think about it.
If you're not sick to your stomach yet, maybe it hasn't sunk in: you're going to have to programmatically visit each page first, before working with their corresponding Web Part collections. This is like cranking a chainsaw--you can't saw until you've cranked the engine.
Actually the chainsaw is a bad metaphor, because you have to crank the chainsaw, then maybe prime the engine with a few squirts of gasoline, then crank the chainsaw again, then adjust the choke, then finally, crank the engine successfully. Then saw.
The point is, you a) do some sort of chainsaw preparatory work, then b) get with the sawing, in strict order.
Alchemy
At times SharePoint feels like alchemy, and today's post most definitely illustrates one of those times. I don't think I should have to use a chainsaw analogy to describe an object collection of any sort. We can call this Peter's Twenty-First Law of Software Engineering Quality: chainsaw analogies may be an indicator of bad code smell.