Skip to content

[Platform][VertexAi] Normalize nullable fields in structured output schema - #2398

Open
ousamabenyounes wants to merge 2 commits into
symfony:mainfrom
ousamabenyounes:fix/issue-1999
Open

ousamabenyounes wants to merge 2 commits into
symfony:mainfrom
ousamabenyounes:fix/issue-1999

Conversation

@ousamabenyounes

@ousamabenyounes ousamabenyounes commented Aug 11, 2026

Copy link
Copy Markdown
Contributor
Q A
Bug fix? yes
New feature? no
Docs? no
Issues Fix #1999
License MIT

Problem

Using structured output with the Vertex/Gemini bridge throws as soon as a DTO property is nullable:

Error from Gemini API: "Invalid JSON payload received. Unknown name "type" at
'generation_config.response_schema.properties[0].value.items.properties[5].value':
Proto field is not repeating, cannot start list."

The JSON Schema factory represents a nullable field with an array-style type ("type": ["string", "null"]). VertexAI's OpenAPI-flavored schema parser does not accept an array there — it requires a single type plus "nullable": true.

Contract\ToolNormalizer already performed this conversion for tool parameter schemas, but the structured-output responseSchema in Gemini\ModelClient was assigned straight from the response_format payload without any normalization, so nullable fields broke.

Fix

  • Extract the nullable-array → nullable: true conversion (and the additionalProperties stripping) from ToolNormalizer into a shared SchemaNormalizer.
  • ToolNormalizer now delegates to it (identical behavior, no duplicated logic).
  • Gemini\ModelClient runs the structured-output responseSchema through the same normalizer, so tool and response schemas stay in sync.

Test verification (RED → GREEN)

New test testItNormalizesNullableFieldsInStructuredOutputResponseSchema asserts the wire responseSchema has a single type + nullable: true (top-level and nested items) and no additionalProperties.

On the unmodified branch (RED):

1) ...VertexAi\Tests\Gemini\ModelClientTest::testItNormalizesNullableFieldsInStructuredOutputResponseSchema
Failed asserting that Array &0 [
    0 => 'string',
    1 => 'null',
] is identical to 'string'.
FAILURES! Tests: 1, Assertions: 2, Failures: 1.

With the fix (GREEN), the whole VertexAi bridge suite (including the existing ToolNormalizer nullable tests, proving behavior parity after the extraction):

OK (109 tests, 457 assertions)

PHPStan and PHP-CS-Fixer are clean on the changed files.

@carsonbot carsonbot added Bug Something isn't working Platform Issues & PRs about the AI Platform component Status: Needs Review labels Aug 11, 2026
…chema

Vertex/Gemini structured output threw "Proto field is not repeating, cannot
start list" whenever a DTO property was nullable: the response schema was sent
with an array-style type (e.g. ["string", "null"]), but VertexAI's
OpenAPI-flavored parser requires a single type plus "nullable": true.

ToolNormalizer already applied that conversion to tool parameter schemas, but
the structured-output responseSchema in Gemini\ModelClient was passed through
raw. Extract the conversion into a shared SchemaNormalizer and run the
responseSchema through it, so tool and response schemas stay in sync.
The bridge-isolated PHPStan shard could not resolve the SchemaNormalizer::normalize()
template type T because the response_format schema is reached through mixed array
access. Read it into a variable and guard with is_array() so the type is concrete.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something isn't working Platform Issues & PRs about the AI Platform component Status: Needs Review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Vertex/Gemini] Nullable fields in structured output throw exception

2 participants