Workaround: fixing Umbraco template not found error

How to fix Umbraco Template not found custom 404 error?

In this post, I am gonna share a quick workaround on how you can resolve the Umbraco CMS Template not found error for published content.

Recently I had a strange issue while trying to render a view for document type (product).

For some reason, the Umbraco engine could not find a template for published content.

After entering the product URL address, a well-known error popped up: 

No template exists to render the document at url '/en/products/coca-cola-0-33l-cherry'.

In addition, no template exists to render the custom 404.

This page can be replaced with a custom 404. Check the documentation for "custom 404".

This page is intentionally left ugly ;-)

Umbraco CMS template not exists, template not found error

It is worth providing more details here to better understand the issue:

  • The product document type was created initially without a template
  • All products were published
  • Then, the template was created and assigned to the document type
  • All products were re-published (with a template assigned)
  • What's funny, when reviewing published product nodes in Umbraco back office - each product had a template assigned
  • Moreover, in the document overview - the hostnames/routing were set correctly 

As I wrote before - the product template was assigned to the document type after the full list of products was published initially.

Maybe something went wrong there.

For some reason, I could not get the template working, even though the back office settings were good.

Let's move to the best part - workaround 🙈.

Workaround - we all love hacks ;]

After a short brainstorm, I decided to create an additional ContentFinder which I named "MissingTemplateContentFinder".

A brief description of the ContentFinder logic:

  • Find content based on request absolute path
  • Check the model type alias, when published content was found, 
  • If we found a product, try to set the template with "product" alias (the product view was Product.cshtml)
  • Return result of the operation (boolean)
public class MissingTemplateContentFinder : IContentFinder
{
   public bool TryFindContent(PublishedRequest request)
   {
      var content = request.UmbracoContext.Content.GetByRoute(request.Uri.AbsolutePath);

      if (content == null) return false;

      if (content.ContentType.Alias == Product.ModelTypeAlias)
      {
         request.PublishedContent = content;

         var result = request.TrySetTemplate("Product");

         return result;
      }

      return false;
   }
}

Note that, when you're having a multilanguage site - you can have issues getting content by the route.

You should follow the great discussion here:

https://github.com/umbraco/Umbraco-CMS/issues/3850 

To make it fully work - I had to modify the request's absolute path a bit.

In my case removing the language from the URL helped, so the final route should be:

'/produkte/coca-cola-0-33l-cherry' instead of '/de/produkte/coca-cola-0-33l-cherry'.

You may also need this trick, so the updated code can look as follows:

public bool TryFindContent(PublishedRequest request)
{
   var content = request.UmbracoContext.Content.GetByRoute(FixRoutePath(request.Uri.AbsolutePath));

   if (content == null) return false;

   if (content.ContentType.Alias == Product.ModelTypeAlias)
   {
      request.PublishedContent = content;

      var result = request.TrySetTemplate("Product");

      return result;
   }

   return false;
}

/// <summary>
/// Fix language issue for route https://github.com/umbraco/Umbraco-CMS/issues/3850 
/// </summary>
/// <param name="absolutePath"></param>
/// <returns></returns>
private string FixRoutePath(string absolutePath)
{
   //Include your languages
   if (absolutePath.StartsWith("/en/") || absolutePath.StartsWith("/de/") || absolutePath.StartsWith("/ru/"))
   {
      return absolutePath.Remove(0, 3);
   }

   return absolutePath;
}

Once the content finder is ready - register MissingTemplateContentFinder into ContentFinders pipeline: 

composition.ContentFinders().InsertBefore<ContentFinderByUrl, MissingTemplateContentFinder>();

Final thoughts

The above workaround did a trick for me and I was able to fix the rendering for the document type.

I have to mention I am not fully happy with this solution ;]

Did you have such a problem?

How did you solve it?

Let me know in the comment below ⬇️.

Comments
Leave a Comment