From 7aa5d4e7857225b555ab0a43255b431c6a8f1fc1 Mon Sep 17 00:00:00 2001 From: Prashant Vasudevan <71649489+vprashrex@users.noreply.github.com> Date: Mon, 7 Sep 2026 11:15:28 +0530 Subject: [PATCH] fix(llm): Drop SDK's snake_case property_ordering from Gemini response schema genai_transformers.t_schema().model_dump() emits snake_case property_ordering (no by_alias), and the mapper's guard only checks camelCase propertyOrdering before adding its own required-order list. The request therefore carries both keys; Vertex merges them into one ordering with every field duplicated and rejects the request with 'property_ordering contains duplicate field ...', failing every google-gcp batch row that uses a json_output_schema. Pop the snake_case key so exactly one ordering (required-field order) is sent. Verified against a live Vertex batch job: previously-failing schema now returns valid structured output. Co-Authored-By: Claude Fable 5 --- backend/app/services/assessment/mappers.py | 4 ++++ backend/app/services/llm/mappers.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/backend/app/services/assessment/mappers.py b/backend/app/services/assessment/mappers.py index 5623222de..95c1ceef7 100644 --- a/backend/app/services/assessment/mappers.py +++ b/backend/app/services/assessment/mappers.py @@ -83,6 +83,10 @@ def _convert_json_schema_to_google(schema: dict) -> dict: else normalized_schema ) + # The SDK's model_dump emits snake_case `property_ordering`; Vertex merges it + # with our camelCase key into a duplicated ordering and rejects the request, + # so keep exactly one ordering key. + google_schema.pop("property_ordering", None) if "properties" in google_schema and "propertyOrdering" not in google_schema: google_schema["propertyOrdering"] = list( normalized_schema.get("required", []) diff --git a/backend/app/services/llm/mappers.py b/backend/app/services/llm/mappers.py index f2e3d7d05..3f1916d82 100644 --- a/backend/app/services/llm/mappers.py +++ b/backend/app/services/llm/mappers.py @@ -127,6 +127,10 @@ def _convert_json_schema_to_google(schema: dict[str, Any]) -> dict[str, Any]: else normalized_schema ) + # The SDK's model_dump emits snake_case `property_ordering`; Vertex merges it + # with our camelCase key into a duplicated ordering and rejects the request, + # so keep exactly one ordering key. + google_schema.pop("property_ordering", None) if "properties" in google_schema and "propertyOrdering" not in google_schema: google_schema["propertyOrdering"] = list( normalized_schema.get("required", [])