ThreadLocal remains set after an exception is thrown during discriminator validation, leading to non-deterministic behavior since that thread is "dirty"

Issue #241 resolved
Keenan Pepper created an issue

This was discovered as a complication of the already known issue #166 (Discriminator validation fails with NPE). I noticed that the error wasn’t happening every time, but instead only happening randomly, while other times the validation would pass with the exact same request.

This is because a node is removed from ThreadLocal DiscriminatorKeywordValidator.visitedNodes after it is visited again in normal operation, but if an exception is thrown (such as that NPE), the ThreadLocal continues to have that node in it, which causes the discriminator validation to be skipped if a server reuses that thread for a subsequent request.

This ThreadLocal should be cleared out when validation is over, perhaps in a finally block.

Comments (5)

  1. Keenan Pepper

    I now realize that this is not a general bug, but an artifact of something wonky I was doing with the schema. It also wasn’t directly related to #166 at all.

    Here’s an example of what my preprocessing was doing to the schema for Pet:

    {
     "required": [
       "id",
       "petType"
     ],
     "type": "object",
     "properties": {
       "id": {
         "type": "string"
       },
       "petType": {
         "type": "string"
       }
     },
     "discriminator": {
       "propertyName": "petType",
       "mapping": {
         "doggie": "Dog"
       }
     },
     "components": {
       "schemas": {
         "Pet": {
           "required": [
             "id",
             "petType"
           ],
           "type": "object",
           "properties": {
             "id": {
               "type": "string"
             },
             "petType": {
               "type": "string"
             }
           },
           "example": {
             "petType": "petType",
             "id": "id"
           },
           "discriminator": {
             "propertyName": "petType",
             "mapping": {
               "doggie": "Dog"
             }
           }
         },
         "Dog": {
           "allOf": [
             {
               "$ref": "#\/components\/schemas\/Pet"
             },
             {
               "$ref": "#\/components\/schemas\/Dog_allOf"
             }
           ]
         },
         "Dog_allOf": {
           "required": [
             "breed"
           ],
           "properties": {
             "breed": {
               "type": "string"
             }
           }
         }
       }
     }
    }
    

    so the issue is that there are two copies of the schema for Pet, and the validator can’t tell that Dog is a possible valid value for the discriminator, because it refers to the wrong Pet instance (the named one rather than the one at root level).

  2. Log in to comment