Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.15.0 - bug in rendering % characters from ValidationError #9295

Closed
smallwat3r opened this issue Mar 18, 2024 · 4 comments · Fixed by #9330
Closed

3.15.0 - bug in rendering % characters from ValidationError #9295

smallwat3r opened this issue Mar 18, 2024 · 4 comments · Fixed by #9330
Labels

Comments

@smallwat3r
Copy link

smallwat3r commented Mar 18, 2024

The new 3.15.0 release introduced a bug in rendering errors from the ValidationError exception class.

Given a serializer:

class MySerializer(Serializer):
    departure_datetime = serializers.DateTimeField(
        required=True,
        format="%Y-%m-%d %H:%M:%S",
        error_messages={"invalid": "Expects format %Y-%m-%d %H:%M:%S"},
    )

Calling ValidationError would raise the exception:

  File "/.../.venv/lib/python3.11/site-packages/rest_framework/fields.py", line 603, in fail
    raise ValidationError(message_string, code=key)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/.../.venv/lib/python3.11/site-packages/rest_framework/exceptions.py", line 160, in __init__
    detail = [detail % params]
              ~~~~~~~^~~~~~~~
ValueError: unsupported format character 'Y' (0x59) at index 27

As expected, this can easily be reproduced in the console:

>>> ValidationError("Expects format %Y-%m-%d %H:%M:%S")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../.venv/lib/python3.11/site-packages/rest_framework/exceptions.py", line 160, in __init__
    detail = [detail % params]
              ~~~~~~~^~~~~~~~
ValueError: unsupported format character 'Y' (0x59) at index 16

or

>>> ["Expects format %Y-%m-%d %H:%M:%S" % {}]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: unsupported format character 'Y' (0x59) at index 16

A solution would be to escape with double % characters any occurrence of % in the error messages.

class MySerializer(Serializer):
    departure_datetime = serializers.DateTimeField(
        required=True,
        format="%Y-%m-%d %H:%M:%S",
        error_messages={"invalid": "Expects format %%Y-%%m-%%d %%H:%%M:%%S"},
    )

Unsure this is a choice by design or not, as this wouldn't be the case on 3.14.x?

@AlanCoding
Copy link

This is coming from #8863, which is very difficult to live with. The original motivation of that, from #8077, had a reason of using more standard Django / python exception argument. But if you look at the Django error behavior:

from django.core.exceptions import ValidationError as dValidationError

dValidationError("Expects format %Y-%m-%d %H:%M:%S")
dValidationError("Expects format %Y-%m-%d %H:%M:%S").error_list

It does no similar formatting when given such a string.

@auvipy
Copy link
Member

auvipy commented Mar 21, 2024

related fix #9313

@tomchristie
Copy link
Member

tomchristie commented Mar 21, 2024

Suggested for 3.15.1... revert #8863.

(I've made a further comment on #9313 wrt. resolving this without introducing a regression.)

@dadamfon
Copy link

dadamfon commented Mar 21, 2024

With the new update, we have encountered a regression issue:

Given the string "%22safe," which is not a format string,
when we attempt to raise a ValidationError with the string,
then raise the error with the following message "%22safe,"
but we encounter the following error: "TypeError: not enough arguments for format string."

Example:

raise ValidationError('%22safe')

Result:

*** rest_framework.exceptions.ValidationError: [ErrorDetail(string='                    {}afe', code='invalid')]
*** TypeError: not enough arguments for format string

Notes:
Take into account that the string does not actually have a format string; it is part of a URL, so we need to print the value properly for the error message, but it interprets it as a format string.

This was referenced Mar 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
5 participants