question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Preferred method for handling pydantic validation errors?

See original GitHub issue

Let’s say I have the following code and the reponse from google is invalid when being loaded into the GoogleTokenValidationResponse schema.

import requests

from ninja.errors import ValidationError


class GoogleTokenValidationResponse(Schema):
    iss: str
    nbf: str
    au: str
    sub: str

def validate_google_credential(id_token: str):
    response = requests.get(
        "https://oauth2url.com, params={"id_token": id_token}
    )

    if not response.ok:
        raise ValidationError("id_token is invalid.")

    response_data = GoogleTokenValidationResponse(**response.json())

    return response_data

The result is a 500 error with a traceback like so:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/ninja/operation.py", line 99, in run
    result = self.view_func(request, **values)
  File "/opt/app/api/authentication/views.py", line 23, in login
    google_response_data = validate_google_credential(
  File "/opt/app/api/authentication/helpers.py", line 96, in validate_google_credential
    response_data = GoogleTokenValidationResponse(**response.json())
  File "/usr/local/lib/python3.10/site-packages/pydantic/main.py", line 342, in __init__
    raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for GoogleTokenValidationResponse
au
  field required (type=value_error.missing)

I’d like to handle this error more elegantly, so I tried catching the Pydantic validation error like so:

import requests

from ninja.errors import ValidationError
from pydantic import ValidationError as PydanticValidationError


def validate_google_credential(id_token: str):
    response = requests.get(
        GoogleOauth.TOKEN_INFO_URL.value, params={"id_token": id_token}
    )

    if not response.ok:
        raise ValidationError("id_token is invalid.")

    try:
        response_data = GoogleTokenValidationResponse(**response.json())
    except PydanticValidationError:
        raise ValidationError("Google response was malformed.")

    return response_data

which gives me a nice 422 error with {"detail": "Google response was malformed."}

I like how this functions, but I’m not too keen on the idea of putting every schema load in to a try/except.

Is there any clean method to catch all pydantic validation errors and handle them so they return 422 errors with a clean error instead of a traceback? I’m not too concerned about the specificity of message, something generic like “error validating data” would be fine, but it would be nice to bee able to hook in something more specific,

Issue Analytics

  • State:open
  • Created 9 months ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
meterskcommented, Dec 9, 2022

Thanks for that very detailed response! It’s quite helpful for me.

1reaction
OtherBarrycommented, Dec 9, 2022

Without knowing anything about the use case of your endpoint or the oauth service you’re using, I can’t give particuarly detailed advice.

My understanding is, you’ve got a function that takes in a token value from the client, sends it to google to validate it, and google sends back data that either you or the client need to perform further actions. These are the possible outputs I see from this process:

  1. The client-provided token is missing, or in an invalid format that you can either tell within your code, or that google will tell you explicitly. In this case a 422 response with standard invalid field response makes the most sense to me.
  2. The client-provided token is formatted validly, but isn’t a valid for your app/endpoint. In this case you’d want to return a 401 or a 403, depending on whether it’s authentication or authorization issue, and potentially some text explaining the issue. My guess is that there’s a specific status code that the google endpoint will return in these situations, or a specifc response.
  3. Google has some kind of error, in which case you’d want to rerturn a 5XX error, because it’s a problem that has nothing to do with the client. Chances are the google endpoint will return a 5XX error in this situation.
  4. Google returns a response that you don’t understand (i.e. doesn’t match your schema) - most likely this is your code not handling a valid google response, in which case it’s pretty reasonable to throw a 500 error (which django will do automatically if an error is thrown) , as it’s a bug in your code.
  5. Google says the token is valid, you get the data back in the format you want, and continue on with whatever you’re doing.

As for exactly what your response contains beyond the error code, that’s pretty use case dependent. If the response is going to something that end users interact with directly (e.g. website or app) then I’d generally return some text that the user can understand. You’d want to make it clear where the error is e.g. “token_id is not a valid token” rather than just “validation error”. If the response is going to just be read by other people’s software, then it can be less user friendly.

Showing a traceback is never a good idea unless you’re the only person that’s going to be seeing the responses. At best people won’t understand it, at worst it’ll reveal a vunerablility in your code.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Validate Your Data with Custom Validators of Pydantic ...
Since a validator works as a class method, the first argument is the class which is named cls as a convention. The second...
Read more >
Strict Type Validation With Pydantic - Section.io
This tutorial will guide the reader on how to type validate the inputs using Pydantic. We will also learn about create custom validators....
Read more >
return list of validation errors on field in pydantic - Stack Overflow
assert len(password) >= min_length, "Password must be at least 8 characters long." ? – CristiFati · I was testing returning a list of...
Read more >
Pydantic V2 Plan
The way line errors (the individual errors within a ValidationError ) are built has become much more sophisticated in pydantic-core. There's a ...
Read more >
Cool Things You Can Do With Pydantic - Medium
Pydantic is a useful library for data parsing and validation. It coerces input types to the declared type (using type hints), accumulates all ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found