Jeremy Davis
Jeremy Davis
Sitecore, C# and web development
Article printed from: https://blog.jermdavis.dev/posts/2016/how-to-shoot-yourself-in-the-foot-with-a-config-patch

How to shoot yourself in the foot with a config patch...

Published 11 July 2016
Updated 25 August 2016
Sitecore ~2 min. read

Sitecore config patches are great, right? We (should) all be using them to ensure that our changes in configuration don't get stomped on when we upgrade, or install new modules. But like any bit of technology, they can sometimes cause problems. Here's an example of one I saw recently, in the hope it can save others from similar issues:

The issue

A colleague reported that a server in a load-balanced production cluster running Sitecore 8.0 had been taken down for a scheduled reboot, but had failed to come back up afterwards. Instead of serving pages, it was now throwing 500 errors for many requests. The Windows Log was filling up with errors like this:

Exception information: 
    Exception type: InvalidOperationException 
    Exception message: Tracker.Current is not initialized
   at Sitecore.Analytics.Pipelines.StartAnalytics.StartTracking.Process(PipelineArgs args)
   at (Object , Object[] )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Mvc.Analytics.Pipelines.MvcEvents.RequestBegin.StartTracking.Process(RequestBeginArgs args)
   at (Object , Object[] )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Mvc.Pipelines.PipelineService.RunPipeline[TArgs](String pipelineName, TArgs args)
   at Sitecore.Mvc.Routing.RouteHttpHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

					

That's not an exception in the custom code for the website – it's Sitecore complaining that something is wrong with the configuration for analytics. Googling for the error brings up a few hits mostly discussing how some specific configuration for "what DNS name is analytics using for this site" can cause this error.

But on the broken server, those analytics config settings were correct.

Cue head scratching...

The cause

Quite by chance, while zipping up config files to drag back to my dev machine for a big "diff all the files" exercise, the colleague who had reported the issue noticed a typo in a configuration patch file. Edited to focus on the issue, it was something like:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>

    <sites>
      <site patch:before="*[@name='website']"
          name="some-other-site"
          hostName="the-analytics-host-name"  
          -- load of other attributes we can ignore -- />
    </sits>

  </sitecore>
</configuration>

					

Somehow the closing tag for the custom <site/> definitions had been mucked up, making the XML in the patch file invalid. Since the host name was not correctly bound requests were falling back to a different <site/> entry, and hence the host name in the analytics wasn't correct. And the tracker goes boom...

Initially, this confused me quite a bit. Surely an invalid configuration file should prevent the site starting? I was expecting to get a 500 error for failing to parse the dodgy XML. So as a test, I applied a similar dodgy patch to a vanilla instance of Sitecore 8. I got the following in the log files:

...
 460 09:23:38 ERROR Could not load configuration file: C:\Inetpub\wwwroot\my-host-name\Website\App_Config\Include\zz_test\broken.config: System.Xml.XmlException: The 'sites' start tag on line 4 position 6 does not match the end tag of 'sits'. Line 8, position 7.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.ThrowTagMismatch(NodeData startTag)
   at System.Xml.XmlTextReaderImpl.ParseEndElement()
   at System.Xml.XmlTextReaderImpl.ParseElementContent()
   at Sitecore.Xml.Patch.XmlReaderSource.<GetChildren>d__4.MoveNext()
   at Sitecore.Xml.Patch.XmlPatchUtils.MergeChildren(XmlNode target, IXmlElement patch, XmlPatchNamespaces ns, Boolean targetWasInserted)
   at Sitecore.Xml.Patch.XmlPatchUtils.MergeChildren(XmlNode target, IXmlElement patch, XmlPatchNamespaces ns, Boolean targetWasInserted)
   at Sitecore.Xml.Patch.XmlPatchUtils.MergeChildren(XmlNode target, IXmlElement patch, XmlPatchNamespaces ns, Boolean targetWasInserted)
   at Sitecore.Configuration.ConfigPatcher.ApplyPatch(TextReader patch, String sourceName)
   at Sitecore.Configuration.ConfigPatcher.ApplyPatch(String filename)
   at Sitecore.Configuration.Factory.LoadAutoIncludeFiles(ConfigPatcher patcher, String folder)
...

					

So while this is recorded as an error int the log, it does not stop startup. Sitecore just ignores the dodgy config patch file and carries on regardless.

That left me wondering if this behaviour changed at some point, or whether I've always just had a wrong expectation of the software's behaviour here. That's something to do some digging about when I have some free time. So probably never then... 😉

But I think the key things to remember here are:

  • Make sure you validate that your patch files are actually valid XML, because stuff can go subtly wrong if they're not.
  • When spelunking config on production servers, your default answer to Notepad asking "do you want to save your changes" should be "no", because 99% of the time you really did not want to change it.
↑ Back to top