Jeremy Davis
Jeremy Davis
Sitecore, C# and web development
Jeremy Davis
Jeremy Davis
Sitecore, C# and web development

Xref links in recent Statiq versions

Something changed, and it broke my build...

Published 23 May 2022

I updated the build project for this blog recently, as the engine used to generate it was updated. But doing that caused an issue which I think others might bump into. So here's an explanation of what I saw and how to fix it:

The issue

In a couple of places in the theme for my blog I make use of xref links. That's a way of writing a link in your source which doesn't directly care where the resulting page will end up. The publishing code will fix-up your link to the correct URL once it's worked out where the target page is.

One place I'm using these links is in the MVP widget on the right hand column. Clicking the image takes you to the relevant page. So in the cshtml for the right column I have a link which says:

<a href="xref:mvp">....</a>

					

and then elsewhere in the project I have a file called mvp.md which defines that page. And that linking had been working fine up until I updated to beta 45. Having done that, I started to see errors:

A list of errors about xref resolution

There's basically one error here, but it's repeated a lot:

[ERRO] Archives/PostProcess » ExecuteSwitch » RenderContentPostProcessTemplates » ResolveXrefs » 15 xref resolution failures:
C:/Users/jeremy.davis/source/repos/blog.jermdavis.dev/StatiqGenerator/theme/input/posts.cshtml
 - Multiple ambiguous matching documents found for xref "mvp"

					

Every time the engine is trying to render any page which has the xref link to the mvp page, it gets this error. Something that changed in beta 45 means it can no longer resolve this link correctly.

Working out the cause

The best place to start with an issue like this is with the release notes for the new version. And looking through that, there is something interesting here:

Expanded xref lookup behavior to look in all relevant pipelines, not just the "content" pipeline 
(exclusions can be customized using the XrefPipelines and AdditionalXrefPipelines settings).

					

Looking through the git commits associated with this release, and thinking about that comment lead me to this extension method: (with some less relevant bits snipped out)

private static TBootstrapper AddDefaultWebSettings<TBootstrapper>(this TBootstrapper bootstrapper)
            where TBootstrapper : IBootstrapper =>
            bootstrapper
                .AddSettingsIfNonExisting(new Dictionary<string, object>
                {
                    {
                        WebKeys.XrefPipelines,
                        new string[]
                        {
                            nameof(Pipelines.Content),
                            nameof(Pipelines.Assets),
                            nameof(Pipelines.Data),
                            nameof(Pipelines.Archives),
                            nameof(Pipelines.Feeds)
                        }
                    }
                });

					

The code is providing the value for a config setting as part of the bootstrap process for the Statiq engine. It's specifying a set of pipelines which are going to be processed to find potential xref targets. I think in the previous version of the code it only looked at the Content pipeline, but now it looks at all the main ones.

So why might this break my site?

It took me a while to work this out. I tried a variety of changes to my theme and content before I realised what was up. But the answer turned out to be my tags. As well as having a markdown page titled "MVP" in the content, I also had a few posts which were tagged "MVP" too. The Archives pipeline generates pages for each tag to list all the posts which have that tag applied. So you end up with HTML files for both the MVP page and for the MVP tag listing.

And now that the outputs of the Archives pipeline are being considered as possible targets for an xref link because of the code changes in this version. And so we have an issue - because as the error says, the code can no longer decide which of the two possible matches is the right one...

Possible answers

I came up with ideas for how this might get sorted:

Option 1 - change the content: Change the name of the MVP page, or the MVP tag.
Whatever they're called, as long as they both have different names, the problem will go away. Of course you'll have to remember not to accidentally cause the same issue again in the future with some other page/tag combination. So any matching combination will cause the error.

Option 2 - change the config: Reconfigure the site to ignore the Archives pipeline.
Alternatively, do you want the xref processing to look at the output of the Archives pipeline? The config in the code above is a setting - which means it can be overridden in the Statiq config files. (Or in your code, if you're choosing to configure things that way) For example I tried adding the following to appsettings.json:

{
  "XrefPipelines": ["Content", "Assets", "Data", "Feeds"]
}

					

That specifies all of the pipelines except the Archives one - so the output file generated for the "MVP" tag will never be considered as a target of my xref. The down side of this is that once you exclude the archive pipeline from this config, you can't use an xref to refer to anything in the archives.

Option 3 - change the links: Make your links without xref.
You could go back to using normal HTML links instead of xref. That would work fine - but it's sort of avoiding the problem.

(And I suppose technically option 4 is "stay on an older version of Statiq" - but that's not a good choice)

I've gone for option 2 here, and my site is generating without errors again.