From 534ba19a826dc93bc5df5191a399f8012875867d Mon Sep 17 00:00:00 2001 From: skfd Date: Fri, 14 Aug 2026 20:34:25 -0400 Subject: [PATCH] Do not crash the host when a template names a table that is gone GetFormattedAttribValue guarded on entity.Attributes but then indexed entity.FormattedValues. An attribute can be present with no formatted value beside it, and the indexer throws KeyNotFoundException when it is, which the catch turned into "Error: Unable to load formatted value for " and rethrew. associatedentitytypecode is that attribute. Dataverse only sends a formatted value for it when it can resolve the table, so a template whose table was deleted, or that was imported from an organization that has one this one does not, comes back as 'none' with nothing formatted. DocumentTemplateEdit reads it unconditionally while building the list, so a single such record failed the whole load -- and because that runs on a background callback, nothing caught it and XrmToolBox went down with it, APPCRASH 0xc000041d rather than an error message. Guarding on the collection actually being indexed returns null instead, and the row renders with an empty Associated Entity cell. Fixes #1 Co-Authored-By: Claude Opus 5 --- Helper/entity.partial.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Helper/entity.partial.cs b/Helper/entity.partial.cs index 1deaaa6..6e0b92d 100644 --- a/Helper/entity.partial.cs +++ b/Helper/entity.partial.cs @@ -33,7 +33,13 @@ public static string GetFormattedAttribValue(this Entity entity, string attribut { try { - if (null != entity && entity.Attributes.Contains(attributeLogicalName)) + // Guard on the collection being indexed, not on Attributes. An attribute can + // be present with no formatted value beside it, and then this indexer throws. + // associatedentitytypecode is the one that bites: Dataverse only sends a + // formatted value for it when it can resolve the table, so a template whose + // table was deleted, or that came from another organization, arrives as + // 'none' with nothing formatted and takes the whole load down with it. + if (null != entity && entity.FormattedValues.Contains(attributeLogicalName)) { return entity.FormattedValues[attributeLogicalName]; }