A Crazy Swagger Bug

I was a new endpoint to an API at work last week when Swagger quit working. Initially, I ignored the error and moved on. I’ve fixed so many Swagger snafus over the years that I knew this was just a distraction. Finally, just before I went on vacation for the holidays, I sat down and investigated the issue. This was a tough bug to figure out. It started with a bug message that made not sense and seems to be a common error for hundreds of issues. Here’s the error I received:

Yeah, it’s obnoxious. Basically, something went wrong when Swagger parsed my code to figure out what endpoints exist and it didn’t report the original error. The swagger.json file doesn’t exist and now it’s reporting that. To make matters worse, my friends Google and StackOverflow led me on a wild goose chase. Everybody has witnessed this error and everyone has a different bug that caused it.

I tried deleting some of my code to see if I could figure out what was causing it. I discovered that one of my controllers had two posts and the Swagger bug went away when I deleted the code for one post or the other. This was curious because both endpoints worked fine with Postman. So I dug a bit deeper. Here is a stripped down version of my posts:

    /// <summary>
    /// first post test
    /// </summary>
    /// <param name="firstPostPoco"></param>
    [HttpPost("first-post")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public void Post1([FromBody] FirstPostPoco firstPostPoco)
    {
    }

    /// <summary>
    /// second post test
    /// </summary>
    /// <param name="secondPostPoco"></param>
    [HttpPost("second-post")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public void Post2([FromBody] SecondPostPoco secondPostPoco)
    {
    }

You can see that the routing is different between the two posts (one is “first-post” and the second is “second-post”).

The next thing I tried was to change the FirstPostPoco into a string type for the post input. This also caused Swagger to work correctly. In fact, I can change FirstPostPoco or SecondPostPoco into a string to make Swagger work correctly.

Digging further into the code I scrutinized the POCOs and the code for both are this:

public class FirstPostPoco
{
    public string ApplicationId { get; set; }

    public List<SubPoco> applicantFollowUpData { get; set; }

    public int applicationTypeId { get; set; }
}

public class SecondPostPoco
{
    public string ApplicationId { get; set; }

    public SubPoco Applicant { get; set; }

    public string Title { get; set; }

    public string Description { get; set; }

    public int ApplicationTypeId { get; set; }
}

These are in two different files, which is standard practice. I used F-12 to dig into the SubPoco (the names of these classes have been changed for this demonstration). The SubPoco looks like this:

public class SubPoco
{
    public int Id { get; set; }

    public string Email { get; set; }

    public string FirstName { get; set; }

    public string MiddleName { get; set; }

    public string LastName { get; set; }
}

I couldn’t figure out where the problem was. The API was setup with Fluent Validation, so I removed all the validation code and removed the NuGet package. That had no effect on the bug.

Next, I created an empty API project and copied my POCOs and Controllers over to the empty project. The minimum code possible. I could not get my test code to break.

As I was observing the code in the main API project, I noticed that the SubPoco for the FirstPostPoco was in a Models folder and the SubPoco for the SecondPostPoco was in another project. Aha!

Seriously, they are both the same class name with the same properties. The code compiled and worked correctly, but Swagger had an issue with it. I’m betting that Swagger keeps a dictionary or array of class names and this collided and caused it to crash. This problem was easy to fix, but it sure was difficult to find.

You can download the sample code from my GitHub account and witness this bug yourself by clicking here.

Leave a Reply