Custom errors and error detail policy in ASP.NET Web API

Today Kurt and I were attempting to debug an Web API service we had deployed to a remote machine. The service was returning 500 errors, and for various reasons, we couldn’t just try to do the requests from that deployed box. We wanted to get the full exception details in the response, but we were just seeing blank 500 errors, with no responses.

We first tried the Web.Config setting for custom errors:

<customErrors mode="Off" />

But this didn’t affect anything. Digging a little further, we found that ASP.NET Web API uses a different configuration for error details being passed along. This is for a couple of reasons; first, the custom errors element in the Web.Config is an ASP.NET thing. It’s something that ASP.NET uses to determine if that yellow screen of death with additional detail should be shown to users. However, ASP.NET Web API is designed to be self-hosted, outside of ASP.NET and IIS. While the customErrors element affects requests for ASPX and MVC, it does nothing for Web API.

Instead of relying on a lot of XML configuration, Web API uses a lot of programmatic configuration. This helps self hosting, but for changing policies like error detail, we have to change the code, re-compile and re-deploy. To set the error policy in our application, we need to modify our global Web API configuration:

    = IncludeErrorDetailPolicy.Always;

With this mode, requests from any source will get us full exception detail. It’s likely not something we want in production, but nice that it is available. We have three familiar options for the IncludeErrorDetailPolicy setting:

  • LocalOnly (default)
  • Always
  • Off

These correspond 1:1 to the customErrror policy in their behavior, but in the reverse. The ASP.NET customErrors setting talks about when to custom errors, where Web API is when to display exception details. Same settings, but approaching from opposite ends.

What if we want to just have Web API use whatever setting that our Web.Config uses? We can just read the ASP.NET setting and apply it to our Web API config:

var config = (CustomErrorsSection)

IncludeErrorDetailPolicy errorDetailPolicy;

switch (config.Mode)
    case CustomErrorsMode.RemoteOnly:
            = IncludeErrorDetailPolicy.LocalOnly;
    case CustomErrorsMode.On:
            = IncludeErrorDetailPolicy.Never;
    case CustomErrorsMode.Off:
            = IncludeErrorDetailPolicy.Always;
        throw new ArgumentOutOfRangeException();

    = errorDetailPolicy;

With this approach, we just set one policy for custom errors in our Web.Config file, and both our MVC/WebForms and WebAPI requests in the same application use the exact same policy, and we have the ability to change this policy after we deploy.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASPNETMVC, ASPNETWebAPI. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1088()

  • Crodriguez

    Jimmy tag search does not work. I always come to your DDD articles by google…Hope you fix it

    • Anonymous

      Hmm that’s weird, we’ll look into it!

      • Dariusz Lenartowicz

        Still it is broken… since I can remember it’s broken. :/


  • Henrik Frystyk Nielsen

    This is a good idea — it would be great if you could log an issue on our codeplex site:



    • Anonymous

      Will do!

  • TheRedCircuit

    I was thinking, would it be easier to use elmah?

    • We thought about it, and will likely put that in place. But for quick debugging, it was confusing that this setting just didn’t work.

  • Thanks for answering the problem I had here: 

    • Anonymous

      Ha, weird that it was closed. I added a comment with some more links.

  • Pingback: Another Tiny Contribution to WebApiContrib | Headspring()

  • Nice work!! Would love to see more post from you on mvc 4.0

  • Also, when hosting  ASP.NET WebAPI  in IIS, add the following to web.config to makes IIS not eat the body of your custom error responses.

    If you’re running IIS7/7.5 on a “security hardened” server, you’ll need to run the following commands to “unlock” that config section:

    cd C:WindowsSystem32inetsrv

    appcmd unlock config /section:httpErrors

    See details here:

    Jan Ove

    • Anonymous

      Ha, that’s much easier than my way, which was unlocking each status code at a time. Thanks!

  • Matt Scully

    I came across this post trying to track down how to get exception details in Web API responses. I thought it worth noting that, as of the official Web API release, this behavior was changed such that Web API _does_ default to the customErrors ASP.NET configuration. If the Web API IncludeErrorDetailPolicy is set to Default, then the ASP.NET customErrors setting is used. If customErrors is not set, the default will be LocalOnly.

    See the “official documentation” (the code) here:
    (Search for “ShouldIncludeErrorDetail”)

  • catholicguy

    Jimmy, I had the below code in my Startup.cs and it does not work in the dev server after deployed.
    GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

    Any suggestions?

    • jbogard

      Nope, sorry!