Skip to content

Warn when blocks receive unexpected fields - #22772

Open
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
fix/block-unexpected-fields-warning
Open

Warn when blocks receive unexpected fields#22772
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
fix/block-unexpected-fields-warning

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

closes #8642

This PR changes behavior: constructing a block with a keyword that isn't a field on the class now emits a UserWarning naming the offending keyword(s), instead of silently storing it as extra data.

Details

Blocks set extra="allow" so that a block document saved under an older schema still loads after a field is removed from the class. That also means a typo is silently accepted:

AwsCredentials(aws_acess_key_id="sentinel")
# no warning; aws_access_key_id is None and the typo only shows up in model_extra

Block.__init__ now checks incoming keywords against field names and aliases (including AliasPath and AliasChoices) and warns when any are unrecognized. Keeping extra="allow" preserves the existing hydration behavior covered by TestBlockSchemaMigration.test_rm_field_from_schema_loads_with_validation.

The warning is only for direct construction of a block. It is skipped when pydantic is validating data into a block — a nested block or a candidate member of a union, where the data may belong to a different type — and when hydrating a persisted block document, so a document that still carries a removed field loads quietly. Persisted-document hydration goes through Block._validate_block_document_data, used by both _from_block_document and the automations loader in server/events/actions.py.

No warning is emitted for block_type_slug or for the _block_document_id/_block_document_name/_is_anonymous keys that ser_model adds to serialized blocks.

Tests in tests/blocks/test_core.py::TestUnexpectedFields cover the typo warning, aliases, alias paths, the discriminator, unions, and removed-field hydration. MockCredentials in tests/runner/test_storage.py now declares the access_token field those tests pass to it.

Checklist

  • This pull request references any related issue by including "closes Raise a warning or error if unexpected keys are passed to Blocks #8642"
    • If no issue exists and your change is not a small fix, please create an issue first.
  • If this is a complex change, a maintainer has confirmed the proposed approach on the linked issue.
  • If this pull request adds or changes functionality, it includes tests or explains why tests are not needed.
  • If this pull request changes user-facing behavior, it updates documentation or explains why documentation is not needed.
  • If this pull request removes docs files, it includes redirect settings in mint.json.
  • If this pull request adds functions or classes, it includes helpful docstrings.

Link to Devin session: https://app.devin.ai/sessions/e46425af6e7546a1b53dfe405057099c
Requested by: @desertaxle

closes #8642

Co-authored-by: alex.s <alex.s@prefect.io>
Co-Authored-By: alex.s <ajstreed1@gmail.com>
@desertaxle desertaxle self-assigned this Aug 10, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions github-actions Bot added the enhancement An improvement of an existing feature label Aug 10, 2026
devin-ai-integration Bot and others added 2 commits August 10, 2026 14:02
Co-authored-by: alex.s <alex.s@prefect.io>
Co-Authored-By: alex.s <ajstreed1@gmail.com>
Co-authored-by: alex.s <alex.s@prefect.io>
Co-Authored-By: alex.s <ajstreed1@gmail.com>
@codspeed-hq

codspeed-hq Bot commented Aug 10, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 8 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing fix/block-unexpected-fields-warning (0696e3a) with main (70deffd)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54397e06f7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/prefect/blocks/core.py Outdated
Comment on lines +918 to +920
token = _hydrating_block_document.set(True)
try:
block = block_cls.model_validate(block_document.data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Suppress warnings in the automation hydration path

Webhook and notification automations hydrate persisted blocks through src/prefect/server/events/actions.py::_load_block_from_block_document, which calls block_cls.model_validate(block_document.data) directly and therefore never sets this context variable. When such a document contains a field removed from the installed block class, automation execution still emits the warning this wrapper is intended to suppress; with warnings treated as errors, the loader catches it and reports the block as invalid. Apply the suppression at every persisted-document hydration entry point or route that loader through a shared helper.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 0696e3a — hydration suppression now lives in Block._validate_block_document_data, and _load_block_from_block_document in server/events/actions.py goes through it instead of calling model_validate directly.

Comment on lines 357 to 359
def __init__(self, *args: Any, **kwargs: Any):
self._warn_on_unexpected_fields(kwargs)
super().__init__(*args, **kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Defer warnings until a union candidate validates

When a block is validated from an untagged dictionary as one member of a union, Pydantic may invoke several candidates before selecting the valid one. Because the warning runs before super().__init__, a failed candidate warns about fields belonging to the successful candidate—for example, validating {"b": 4} against A | B warns from A before B succeeds. Under a warnings-as-errors policy, this can reject otherwise valid input, so only warn after the candidate itself has validated successfully. This changes behavior on the public Block construction API, which requires backward compatibility.

AGENTS.md reference: src/prefect/AGENTS.md:L5-L7

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 0696e3a. The warning now runs after super().__init__, and is skipped entirely when Block.__init__ was invoked by pydantic validating data into a block (nested block or union candidate) rather than by a direct call. Test added for an untagged Union[Left, Right] of blocks under warnings-as-errors.

Comment thread src/prefect/blocks/core.py Outdated
Comment on lines +394 to +399
elif isinstance(field.validation_alias, AliasChoices):
known_names.update(
choice
for choice in field.validation_alias.choices
if isinstance(choice, str)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Recognize AliasPath inputs before warning

Pydantic also permits validation_alias=AliasPath("payload", "x"), and permits an AliasPath inside AliasChoices; in that case Block(payload={"x": 1}) is valid and consumes payload, but this code records only string choices and incorrectly warns that payload is unexpected. Include the leading input key from AliasPath values so valid public block constructors do not emit—or, with warnings treated as errors, raise—this new warning.

AGENTS.md reference: src/prefect/AGENTS.md:L5-L7

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 0696e3aAliasPath (standalone and inside AliasChoices) now contributes its leading input key to the known names, with a test covering validation_alias=AliasPath("payload", "x").

Co-authored-by: alex.s <alex.s@prefect.io>
Co-Authored-By: alex.s <ajstreed1@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement An improvement of an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Raise a warning or error if unexpected keys are passed to Blocks

1 participant