Skip to content

Emit warning when field-specific metadata is used in invalid contexts#12028

Merged
Viicos merged 9 commits intomainfrom
field-info-attr-warning
Jul 18, 2025
Merged

Emit warning when field-specific metadata is used in invalid contexts#12028
Viicos merged 9 commits intomainfrom
field-info-attr-warning

Conversation

@Viicos
Copy link
Copy Markdown
Member

@Viicos Viicos commented Jun 30, 2025

Best reviewed commit per commit.

In a nutshell, this now raises a warning:

from typing import Annotated

from pydantic import BaseModel, Field

type MyInt = Annotated[int, Field(alias='my_alias')]

class Model(BaseModel):
    # see the warning in https://docs.pydantic.dev/latest/concepts/types/#named-type-aliases for more info:
    a: MyInt
"""
>>> UnsupportedFieldAttributeWarning: The 'alias' attribute with value 'my_alias' was provided to the `Field()` function, which 
>>> is unsupported in the context it was used. 'alias' is field-specific metadata, and can only be attached to a model field 
>>> using `Annotated` metadata or by assignment (note that using `Annotated` type aliases using the `type` statement 
>>> isn't supported).
"""

# Other use case:
class Model(BaseModel):
    a: list[Annotated[int, Field(default=1)]]
"""
>>> UnsupportedFieldAttributeWarning: The 'default' attribute with value 1 was provided to the `Field()` function, which 
>>> is unsupported in the context it was used. 'alias' is field-specific metadata, and can only be attached to a model field 
>>> using `Annotated` metadata or by assignment (note that using `Annotated` type aliases using the `type` statement 
>>> isn't supported).
"""

We still need to figure out if we want the warning to be raised for default and default_factory. Currently, the following works:

type MyInt = Annotated[int, Field(default=1)]

class Model(BaseModel):
    a: MyInt

Model()
#> Model(a=1)

This is explained by the fact that we need to support defaults in type adapters:

TypeAdapter(Annotated[int, Field(default=1)]).get_default_vaue()
#> Some(1)

And as a consequence it accidentally worked for models as well. However, things are inconsistent:

type MyInt = Annotated[int, Field(default=1)]

class Model(BaseModel):
    a: MyInt

Model.model_fields['a'].is_required()  # True

and JSON Schema generation is also acting weirdly: #12024.

Imo, I think we should keep the warning for default and default_factory. Sure, validation behavior still works, but it is a footgun for the reasons mentioned above. Users can still ignore the warning if they feel like it.


I've reached out to the FastAPI team regarding the failing tests. They will need to address them in some way.

@github-actions github-actions Bot added the relnotes-fix Used for bugfixes. label Jun 30, 2025
Comment on lines -416 to -429
def _warn_on_nested_alias_in_annotation(ann_type: type[Any], ann_name: str) -> None:
FieldInfo = import_cached_field_info()

args = getattr(ann_type, '__args__', None)
if args:
for anno_arg in args:
if typing_objects.is_annotated(get_origin(anno_arg)):
for anno_type_arg in _typing_extra.get_args(anno_arg):
if isinstance(anno_type_arg, FieldInfo) and anno_type_arg.alias is not None:
warnings.warn(
f'`alias` specification on field "{ann_name}" must be set on outermost annotation to take effect.',
UserWarning,
)
return
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was fragile logic implemented a long time ago, that is now fully covered by the new warning.

Comment thread pydantic/_internal/_generate_schema.py Outdated
Comment on lines +582 to +587
with warnings.catch_warnings():
# We kind of abused `Field()` default factories to be able to specify
# the `defaultdict`'s `default_factory`. As a consequence, we get warnings
# as normally `FieldInfo.default_factory` is unsupported in the context where
# `Field()` is used and our only solution is to ignore them (note that this might
# wrongfully ignore valid warnings, e.g. if the `value_type` to a PEP 695 type alias
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is referring to the following use case:

class Model(BaseModel):
    a: defaultdict[int, Annotated[list[int], Field(default_factory=lambda: MyList())]]

Comment on lines +1556 to +1559
# Because we pass `field` as metadata above (required for attributes relevant for
# JSON Scheme generation), we need to ignore the potential warnings about `FieldInfo`
# attributes that will not be used:
check_unsupported_field_info_attributes=False,
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for validated function calls (see test_unsupported_field_attribute_nested_with_function()). We don't want to raise a warning for:

@validate_call
def func(a: Annotated[int, Field(alias='b')]): ...

Comment thread pydantic/_internal/_generate_schema.py Outdated
@Viicos Viicos requested review from DouweM and davidhewitt June 30, 2025 17:40
@Viicos Viicos added relnotes-change Used for changes to existing functionality which don't have a better categorization. needs-blogpost-entry This PR needs to be documented in the release notes blog post and removed relnotes-fix Used for bugfixes. labels Jun 30, 2025
@github-actions
Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  pydantic
  functional_validators.py
  warnings.py
  pydantic/_internal
  _fields.py
  _generate_schema.py
Project Total  

This report was generated by python-coverage-comment-action

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Jun 30, 2025

CodSpeed Performance Report

Merging #12028 will not alter performance

Comparing field-info-attr-warning (705951a) with main (dac3c43)

Summary

✅ 46 untouched benchmarks

@Viicos Viicos added the third-party-tests Add this label on a PR to trigger 3rd party tests label Jun 30, 2025
@Viicos Viicos closed this Jun 30, 2025
@Viicos Viicos reopened this Jun 30, 2025
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jun 30, 2025

Deploying pydantic-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 705951a
Status: ✅  Deploy successful!
Preview URL: https://e6f68bfe.pydantic-docs.pages.dev
Branch Preview URL: https://field-info-attr-warning.pydantic-docs.pages.dev

View logs

@Viicos Viicos force-pushed the field-info-attr-warning branch from 59be012 to 6c868fa Compare June 30, 2025 20:04
Comment thread pydantic/_internal/_generate_schema.py Outdated
Comment thread pydantic/_internal/_generate_schema.py Outdated
Comment thread pydantic/_internal/_generate_schema.py Outdated
@Viicos Viicos force-pushed the field-info-attr-warning branch from 91fc505 to 30acc55 Compare July 1, 2025 15:04
@Viicos
Copy link
Copy Markdown
Member Author

Viicos commented Jul 1, 2025

I'm wondering if, similar to usage errors, we should link to a new documentation section about warnings, to show examples of this issue.

@DouweM
Copy link
Copy Markdown
Contributor

DouweM commented Jul 1, 2025

@Viicos If we haven't documented yet that this is unsupported, I agree we should

@Viicos
Copy link
Copy Markdown
Member Author

Viicos commented Jul 1, 2025

Well it is documented, but I was thinking about linking to the docs from the warning message, so that users don't get confused when they see it.

@DouweM
Copy link
Copy Markdown
Contributor

DouweM commented Jul 1, 2025

@Viicos Ah I like that!

@Viicos
Copy link
Copy Markdown
Member Author

Viicos commented Jul 5, 2025

@Viicos Ah I like that!

Actually this is going to be a bit hard to implement as is, as we'll need to set up the same logic as for errors (that is, construct the URL from the current version, etc). I improved the warning message and we can revisit if users still get confused.

@Viicos Viicos force-pushed the field-info-attr-warning branch from b87d649 to 705951a Compare July 5, 2025 10:21
@Viicos Viicos merged commit 3a7fe26 into main Jul 18, 2025
85 of 90 checks passed
@Viicos Viicos deleted the field-info-attr-warning branch July 18, 2025 08:22
@kamzil
Copy link
Copy Markdown

kamzil commented Oct 31, 2025

Any pointers on how to get rid of these warnings? We're getting hundreds of them in our project after updating to pydantic 2.12, and it's not really clear what they are about. Is Field not supposed to be used together with Annotated? Any proposed workarounds documented somewhere?

@Viicos
Copy link
Copy Markdown
Member Author

Viicos commented Oct 31, 2025

@kamzil

The OP of this PR shows the two cases where the warning will be emitted. If you are using FastAPI, you can try upgrading to >=0.118.1.

@kamzil
Copy link
Copy Markdown

kamzil commented Oct 31, 2025

Thanks for the pointer to update fastapi. Even after updating to the latest version the warnings remain. I did some more digging, and this only seems to happen in test cases where we're using some fastapi routers. Strangely the warnings are output for each field used in the model that's set as request or some other dependency in the router. So could be still related to fastapi.

@Viicos
Copy link
Copy Markdown
Member Author

Viicos commented Oct 31, 2025

Interesting. I assume your code is closed source, but maybe you could paste the traceback when the warning is raised (which should be treated as an error by pytest)? So that I can see where in the FastAPI code this is happening.

@kamzil
Copy link
Copy Markdown

kamzil commented Oct 31, 2025

Here's a minimal example to reproduce:
mytest.py:

from typing import Annotated

import pytest
from fastapi import FastAPI, Query
from fastapi.testclient import TestClient
from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel


class BaseModelCamelCase(BaseModel):
    model_config = ConfigDict(alias_generator=to_camel)


class MyModel(BaseModelCamelCase):
    a: str

app = FastAPI()

@app.get("/a")
async def endpoint(request: Annotated[MyModel, Query()]): ...

client = TestClient(app, raise_server_exceptions=True)

@pytest.mark.asyncio
async def test_a():
    client.get("/a", params={"a": "test"})

With this, I get this output with pytest mytest.py:

mytest.py::test_a
  .venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py:2249: UnsupportedFieldAttributeWarning: The 'alias' attribute with value 'a' was provided to the `Field()` function, which has no effect in the context it was used. 'alias' is field-specific metadata, and can only be attached to a model field using `Annotated` metadata or by assignment. This may have happened because an `Annotated` type alias using the `type` statement was used, or if the `Field()` function was attached to a single member of a union type.
    warnings.warn(

mytest.py::test_a
  .venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py:2249: UnsupportedFieldAttributeWarning: The 'validation_alias' attribute with value 'a' was provided to the `Field()` function, which has no effect in the context it was used. 'validation_alias' is field-specific metadata, and can only be attached to a model field using `Annotated` metadata or by assignment. This may have happened because an `Annotated` type alias using the `type` statement was used, or if the `Field()` function was attached to a single member of a union type.
    warnings.warn(

mytest.py::test_a
  .venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py:2249: UnsupportedFieldAttributeWarning: The 'serialization_alias' attribute with value 'a' was provided to the `Field()` function, which has no effect in the context it was used. 'serialization_alias' is field-specific metadata, and can only be attached to a model field using `Annotated` metadata or by assignment. This may have happened because an `Annotated` type alias using the `type` statement was used, or if the `Field()` function was attached to a single member of a union type.

If I change MyModel to inherit BaseModel instead of BaseModelCamelCase, the warnings go away.

@Viicos
Copy link
Copy Markdown
Member Author

Viicos commented Oct 31, 2025

Are you sure you correctly upgraded to the FastAPI version I mentioned? I get the warning on <0.118.1, but not on >=0.118.1.

@kamzil
Copy link
Copy Markdown

kamzil commented Oct 31, 2025

Must have had some leftovers from the old fastapi or its related libs in my venv, as nuking the whole environment worked. No more warnings. Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-blogpost-entry This PR needs to be documented in the release notes blog post relnotes-change Used for changes to existing functionality which don't have a better categorization. third-party-tests Add this label on a PR to trigger 3rd party tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants