Skip to content

fix(workflow): preserve explicit null values in typed node inputs - #7430

Open
hulkbig wants to merge 14 commits into
google:mainfrom
hulkbig:tmp/fix-workflow-nullable-input-20261006
Open

hulkbig wants to merge 14 commits into
google:mainfrom
hulkbig:tmp/fix-workflow-nullable-input-20261006

Conversation

@hulkbig

@hulkbig hulkbig commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Describe the bug

Workflow input normalization drops valid nullable fields by serializing Pydantic models with exclude_none=True. A required nullable value becomes missing before the function validates its input again, and explicit null on a field with a non-null default can silently become that default, including in nested models.

Preserve None during input normalization with a keyword-only exclude_none option on validate_node_data. Its existing True default retains output validation and other callers' behavior. Regressions cover required/defaulted/nested nulls, omitted fields, message and predecessor inputs, and model/list/dictionary serialization.

Reproduction

Define a model with value: str | None and a workflow function accepting node_input of that model type. Run Workflow(edges=[(START, consume)]) through InMemoryRunner with a user message containing {"value": null}, or pass {'value': None} from a preceding node. Before the fix, this raises Field required; a non-null field default instead replaces explicit null. After the fix, explicit null reaches the function as None, an omitted field uses its default, and an omitted required nullable field remains invalid.

The seven public-workflow regressions give four failures and three control passes with the pristine base methods; all seven pass with this change. The original built-wheel replay through InMemoryRunner also passes all seven scenarios. No model API is involved.

Current revision and verification

Head f9ec32a162deb578191142a4133f3c6d347ace39 normally merges upstream main bcac35a6efb21f176eef9d28d663db247f4e5afd. The net PR diff is the original four-file nullable-input fix (141 insertions, 3 deletions). The earlier GKE fixture correction is now present in main and no longer appears in this diff.

  • Python 3.11.17, existing isolated test environment, checkout src selected explicitly: full workflow and utils suites plus GKE executor tests: 1,675 passed, 3 xfailed, zero failures/errors.
  • Sdist and wheel build; changed-file Ruff, isort, Pyink, license, compliance, guide-link and spelling hooks pass. The generic staged-new-file hook also inspected upstream-only additions and reported four missing unit guides. Running the same repository checker against the actual PR's added-file set passes (there are no new production files). No waiver or hook change was added.
  • git diff --check passes.

Earlier full Python 3.11–3.14 matrix evidence was collected at dad5ca17894ad4a0c34962326db118d24e7f0181; later 6,814-test scoped checks per version were collected at b80d408ba012cdcc7a786ca6e249d832c7a0a3bc. These are historical results, not full-matrix validation of this new head. The current sync is covered by the focused execution above; hosted CI and maintainer review remain pending.

AI assistance was used for implementation, review and validation.

hulkbig added 12 commits October 6, 2026 23:01
AI-assisted implementation and independent AI review. Temporary own-fork review branch, part 1 of 4; not submitted as an upstream contribution. This commit alone is incomplete.

Preserve None only when requested for input normalization. The complete four-file change was tested: 143 focused tests passed; independent InMemoryRunner matrix verified 11 expected behaviors. Broader related run: 1218 passed, 1 skipped, 5 xfailed, 9 setup errors from missing mocker; an A2A-dependent module was excluded.

Formatting checks, full pre-commit, tox/Python-version matrix, complete suite, and clean-wheel E2E remain unverified.
AI-assisted implementation and independent AI review. Temporary own-fork review branch, part 2 of 4; not submitted as an upstream contribution. Regression test files follow.

The complete four-file change passed 143 focused tests and an independent 11-behavior InMemoryRunner matrix. Full formatter/pre-commit checks, complete repository suite, tox/Python-version matrix, and clean-wheel E2E remain unverified.
AI-assisted implementation and independent AI review. Temporary own-fork review branch, part 3 of 4; not submitted as an upstream contribution. Workflow regression test file follows.

The complete four-file change passed 143 focused tests and an independent 11-behavior InMemoryRunner matrix. Full formatter/pre-commit checks, complete repository suite, tox/Python-version matrix, and clean-wheel E2E remain unverified.
Input normalization currently omits validated BaseModel fields whose value is None. Re-validating that normalized input can reject a required nullable field or replace an explicit None with a non-None default. Preserve None only for input normalization and retain the existing output-schema omission behavior.

Add regression coverage for message and dictionary inputs, nullable defaults, nested models, and missing required nullable fields.

AI-assisted implementation and independent AI review. Temporary review branch; formatting checks are incomplete. Not submitted as an upstream contribution. This completes the four reviewed files.

Verification on Python 3.12.14:
- Pristine-baseline new Workflow cases: 4 failed, 3 passed.
- Patched focused tests: 143 passed.
- Independent public InMemoryRunner matrix: 11 expected behaviors verified.
- git diff --check, compileall, and repository compliance checks passed.
- Broader related run: 1218 passed, 1 skipped, 5 xfailed, 9 setup errors from a missing mocker fixture; an A2A-dependent module was excluded.

Limits: full pre-commit/formatter checks, tox/Python-version matrix, complete repository suite, and clean-wheel E2E remain unverified. This input-only change does not alter typed output None omission or other repeated-coercion behavior.
Apply the configured pyink formatting to the two regression test files.
Their ASTs and the production implementation are unchanged.

AI assistance: OpenAI Codex assisted formatting and validation.
Preserve all upstream sync-generator tests and nullable-input regressions.
Related workflow/schema/runner suite: 1285 passed, 1 skipped, 5 xfailed.
Four-file pre-commit framework passed without changing bytes.

AI assistance was used for conflict resolution and validation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant