[GH-ISSUE #5201] [Bug] Gemini-backed clients still reject the whole tool catalog: advertised empty-string const in trace_application_feature.seed.value serializes as an empty enum member #3192

Closed
opened 2026-10-31 00:37:41 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @carcraze on GitHub (Oct 19, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5201

Originally assigned to: @kaoru0822-kitauji on GitHub.

Summary

REA 6.7.0 fixed the boolean-const family (#4025, a2e30168a), and a tools/list scan now shows 0 non-string const/enum — but one advertised empty-string const remains, and it still makes every Gemini request fail. Clients that render const as a one-member enum produce enum: [""], and Google rejects empty enum members with enum[0]: cannot be empty. This issue isolates the exact remaining trigger behind the user-facing report in #4620.

Environment

rea-agents 6.7.0 (npm latest; also present on main)
Node 24.22.0
Client opencode 1.18.32, Google Gemini provider (every Gemini model)
Transport MCP stdio, npx -y rea-agents@6.7.0 mcp

Observed error

GenerateContentRequest.tools[0].function_declarations[243].parameters.properties[seed].any_of[1].properties[value].enum[0]: cannot be empty
GenerateContentRequest.tools[0].function_declarations[243].parameters.properties[seed].any_of[2].any_of[1].properties[value].enum[0]: cannot be empty
GenerateContentRequest.tools[0].function_declarations[243].parameters.properties[seed].any_of[3].any_of[1].properties[value].enum[0]: cannot be empty

Where the value is advertised (observed)

Method: MCP stdio handshake (initialize -> notifications/initialized -> tools/list), then a recursive walk of every inputSchema collecting non-string and empty-string const/enum values. On rea-agents@6.7.0: 207 tools, exactly 1 tool affected, 3 occurrences (none in any other tool; same result in the compact profile):

tool path
trace_application_feature properties.seed.anyOf[1].properties.value.const = ""
trace_application_feature properties.seed.anyOf[2].anyOf[1].properties.value.const = ""
trace_application_feature properties.seed.anyOf[3].anyOf[1].properties.value.const = ""

This matches the failing declaration's seed -> any_of[1/2/3] -> value -> enum[0] path exactly. Non-string consts/enums: none in either profile (the #4025 fix holds).

Why it fails

Source-derived: the canonical schema selects branch variants with z.literal("") (exact empty route/string value); the advertised projection keeps const: ""; the client's declaration rendering maps const to a one-member enum; Google requires enum members to be non-empty strings, so the whole catalog is rejected.

Expected / suggestion

Extend the literal presentation added for #4025 to empty-string literals: advertise the field as type: "string" (keeping default/description) instead of const: "", and relax affected oneOf groups to anyOf where the widened literal distinguished overlapping branches (same rationale as a2e30168a). Canonical Zod validation stays unchanged. A catalog-wide test can assert no non-string and no empty-string const/enum in either profile.

Happy to open a PR for this.

#4025 (boolean const family; fixed in a2e30168a), #4620 (Gemini CLI user report), #5067 (docs diagnostic proposal).

Originally created by @carcraze on GitHub (Oct 19, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5201 Originally assigned to: @kaoru0822-kitauji on GitHub. ### Summary REA 6.7.0 fixed the boolean-`const` family (#4025, a2e30168a), and a `tools/list` scan now shows 0 non-string `const`/`enum` — but one advertised **empty-string** `const` remains, and it still makes every Gemini request fail. Clients that render `const` as a one-member `enum` produce `enum: [""]`, and Google rejects empty enum members with `enum[0]: cannot be empty`. This issue isolates the exact remaining trigger behind the user-facing report in #4620. ### Environment | | | |---|---| | rea-agents | `6.7.0` (npm latest; also present on `main`) | | Node | `24.22.0` | | Client | opencode `1.18.32`, Google Gemini provider (every Gemini model) | | Transport | MCP stdio, `npx -y rea-agents@6.7.0 mcp` | ### Observed error ``` GenerateContentRequest.tools[0].function_declarations[243].parameters.properties[seed].any_of[1].properties[value].enum[0]: cannot be empty GenerateContentRequest.tools[0].function_declarations[243].parameters.properties[seed].any_of[2].any_of[1].properties[value].enum[0]: cannot be empty GenerateContentRequest.tools[0].function_declarations[243].parameters.properties[seed].any_of[3].any_of[1].properties[value].enum[0]: cannot be empty ``` ### Where the value is advertised (observed) Method: MCP stdio handshake (`initialize` -> `notifications/initialized` -> `tools/list`), then a recursive walk of every `inputSchema` collecting non-string **and** empty-string `const`/`enum` values. On `rea-agents@6.7.0`: 207 tools, exactly **1 tool affected, 3 occurrences** (none in any other tool; same result in the `compact` profile): | tool | path | |---|---| | `trace_application_feature` | `properties.seed.anyOf[1].properties.value.const = ""` | | `trace_application_feature` | `properties.seed.anyOf[2].anyOf[1].properties.value.const = ""` | | `trace_application_feature` | `properties.seed.anyOf[3].anyOf[1].properties.value.const = ""` | This matches the failing declaration's `seed -> any_of[1/2/3] -> value -> enum[0]` path exactly. Non-string consts/enums: none in either profile (the #4025 fix holds). ### Why it fails Source-derived: the canonical schema selects branch variants with `z.literal("")` (exact empty route/string value); the advertised projection keeps `const: ""`; the client's declaration rendering maps `const` to a one-member `enum`; Google requires enum members to be non-empty strings, so the whole catalog is rejected. ### Expected / suggestion Extend the literal presentation added for #4025 to empty-string literals: advertise the field as `type: "string"` (keeping `default`/`description`) instead of `const: ""`, and relax affected `oneOf` groups to `anyOf` where the widened literal distinguished overlapping branches (same rationale as a2e30168a). Canonical Zod validation stays unchanged. A catalog-wide test can assert no non-string and no empty-string `const`/`enum` in either profile. Happy to open a PR for this. ### Related #4025 (boolean const family; fixed in a2e30168a), #4620 (Gemini CLI user report), #5067 (docs diagnostic proposal).
Author
Owner

@XinwangTao commented on GitHub (Oct 19, 2026):

Good isolation — this is the same const-to-enum rendering trap as #4025, with z.literal("") slipping through because empty-string literals were left out of that fix. Agree that advertising the field as type: "string" (keeping default/description) instead of const: "" is the right approach, and the oneOf→anyOf relaxation for overlapping branches matches the a2e3016 rationale. One suggestion: extend the catalog-wide test to also reject empty-string const/enum in both profiles — that would have caught this right after 6.7.0 shipped.

<!-- gh-comment-id:6262638324 --> @XinwangTao commented on GitHub (Oct 19, 2026): Good isolation — this is the same const-to-enum rendering trap as #4025, with z.literal("") slipping through because empty-string literals were left out of that fix. Agree that advertising the field as type: "string" (keeping default/description) instead of const: "" is the right approach, and the oneOf→anyOf relaxation for overlapping branches matches the a2e3016 rationale. One suggestion: extend the catalog-wide test to also reject empty-string const/enum in both profiles — that would have caught this right after 6.7.0 shipped.
Author
Owner

@matbrgz commented on GitHub (Oct 19, 2026):

Cross-referencing with sibling MCP client schema validation issues in Cluster A: #3408, #4058, #4081, #2813, and #4736. Different client engines reject advertised tool catalog schemas for divergent serialization defects: while Claude Desktop and VS Code reject deep nesting or items-less array tuples, Gemini-backed engines fail entirely on empty-string const literals rendered as empty enum members.

Consolidated under Cluster A in tracker #4330.

<!-- gh-comment-id:6270803384 --> @matbrgz commented on GitHub (Oct 19, 2026): Cross-referencing with sibling MCP client schema validation issues in **Cluster A**: #3408, #4058, #4081, #2813, and #4736. Different client engines reject advertised tool catalog schemas for divergent serialization defects: while Claude Desktop and VS Code reject deep nesting or items-less array tuples, Gemini-backed engines fail entirely on empty-string const literals rendered as empty enum members. Consolidated under Cluster A in tracker #4330.
Author
Owner

@XinwangTao commented on GitHub (Oct 20, 2026):

Thanks for grouping these — the Cluster A pattern is consistent: different client engines reject the advertised catalog for divergent serialization defects, and this one is the Gemini-side empty-enum rendering of z.literal(""). The #5203 fix (advertise as typed string, relax oneOf→anyOf where branches overlap) mirrors a2e3016, so it should join the same regression story — extending the catalog-wide test to reject empty-string const/enum alongside non-string ones closes the gap for both profiles. Agree with keeping this visible under Cluster A until #5203 merges.

<!-- gh-comment-id:6281050143 --> @XinwangTao commented on GitHub (Oct 20, 2026): Thanks for grouping these — the Cluster A pattern is consistent: different client engines reject the advertised catalog for divergent serialization defects, and this one is the Gemini-side empty-enum rendering of z.literal(""). The #5203 fix (advertise as typed string, relax oneOf→anyOf where branches overlap) mirrors a2e3016, so it should join the same regression story — extending the catalog-wide test to reject empty-string const/enum alongside non-string ones closes the gap for both profiles. Agree with keeping this visible under Cluster A until #5203 merges.
Author
Owner

@huaiqing-afk commented on GitHub (Oct 21, 2026):

Another remaining trigger, different from the empty-string enum in this issue: items declared as oneOf/anyOf with no type.

Observed error

Through a Gemini-backed route (Antigravity gemini-3.8-flash), every turn fails with:

Antigravity: * GenerateContentRequest.tools[0].function_declarations[67].parameters.properties[functions].items.items: field predicate failed: $type == Type.ARRAY
* GenerateContentRequest.tools[0].function_declarations[70].parameters.properties[actions].items.items: field predicate failed: $type == Type.ARRAY
* GenerateContentRequest.tools[0].function_declarations[92].parameters.properties[static_comparisons].items.items: field predicate failed: $type == Type.ARRAY
... (19 lines total)

Deterministic — every retry sends the same declarations and fails identically. Not a quota/account problem.

Environment

rea-agents 6.7.0 (npm)
Client Codex Desktop → magpie gateway → Antigravity (gemini-3.8-flash)
Transport MCP stdio, rea.mjs mcp
REA_MCP_INPUT_SCHEMA_PROFILE compact (set, does not help)
REA_MCP_OUTPUT_SCHEMA_PROFILE off
Observed 2026-10-21, 54 consecutive failed turns

Minimal schema shapes

mcp__rea__capture_browser_scenario → actions:

{
  "actions": {
    "minItems": 1,
    "type": "array",
    "items": {
      "oneOf": [
        { "type": "object", "properties": { "step_id": {...}, "kind": {...} }, "required": [...] },
        { "type": "object", "properties": { ... } }
      ]
    }
  }
}

mcp__rea__build_call_path → functions[].subject:

{
  "subject": {
    "anyOf": [
      { "oneOf": [ { "type": "object", "properties": { ... } } ] },
      { "type": "string" }
    ]
  }
}

Both are valid JSON Schema: the element accepts more than one shape.

Why it fails

A Gemini function-declaration validator requires every items node to carry type: "array" (or a concrete type). When the gateway flattens the schema to the OpenAPI subset Gemini accepts, oneOf/anyOf is dropped but the outer type: "array" + items survive — leaving items with no type, and the request is rejected with $type == Type.ARRAY.

Same class as the enum: [""] in this issue and the array-without-items family (#2784 / #2826 upstream-reporting on the gateway side), but a distinct trigger that survives the 6.7.0 const/enum fixes.

Scope

Of 309 advertised tools in one session, 32 carry an items that is a oneOf/anyOf union with no type:

build_call_path, build_reconstruction_obligation_ledger, capture_browser_scenario,
capture_electron_scenario, capture_native_ui_scenario, compare_application_versions,
compare_artifacts, compare_bundles, compare_functions, correlate_static_and_runtime,
find_changed_behavior, import_managed_reconstruction,
project_android_application_graph, project_apple_application_graph,
project_harmony_application_graph, reconcile_javascript_runtime,
trace_application_feature, verify_managed_native_boundaries, ... (32 total)

Suggestion

In the compact input-schema projection, when a node is type: "array" and its items carries only oneOf/anyOf, derive a single type for items from the first branch (object when all branches are objects, else string) rather than emitting an untyped items.

compact alone does not cover this shape today — consistent with the note in #5067 that the profile cannot guarantee API acceptance.

Cross-reference

Reported on the gateway side too, since a plainSchema fallback there would fix every MCP at once rather than REA alone: yetone/magpie#3173.

<!-- gh-comment-id:6314667846 --> @huaiqing-afk commented on GitHub (Oct 21, 2026): Another remaining trigger, different from the empty-string `enum` in this issue: **`items` declared as `oneOf`/`anyOf` with no `type`**. ## Observed error Through a Gemini-backed route (Antigravity `gemini-3.8-flash`), every turn fails with: ```text Antigravity: * GenerateContentRequest.tools[0].function_declarations[67].parameters.properties[functions].items.items: field predicate failed: $type == Type.ARRAY * GenerateContentRequest.tools[0].function_declarations[70].parameters.properties[actions].items.items: field predicate failed: $type == Type.ARRAY * GenerateContentRequest.tools[0].function_declarations[92].parameters.properties[static_comparisons].items.items: field predicate failed: $type == Type.ARRAY ... (19 lines total) ``` Deterministic — every retry sends the same declarations and fails identically. Not a quota/account problem. ## Environment | | | |---|---| | rea-agents | `6.7.0` (npm) | | Client | Codex Desktop → magpie gateway → Antigravity (`gemini-3.8-flash`) | | Transport | MCP stdio, `rea.mjs mcp` | | `REA_MCP_INPUT_SCHEMA_PROFILE` | `compact` (set, does not help) | | `REA_MCP_OUTPUT_SCHEMA_PROFILE` | `off` | | Observed | 2026-10-21, 54 consecutive failed turns | ## Minimal schema shapes `mcp__rea__capture_browser_scenario` → `actions`: ```json { "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "step_id": {...}, "kind": {...} }, "required": [...] }, { "type": "object", "properties": { ... } } ] } } } ``` `mcp__rea__build_call_path` → `functions[].subject`: ```json { "subject": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { ... } } ] }, { "type": "string" } ] } } ``` Both are valid JSON Schema: the element accepts more than one shape. ## Why it fails A Gemini function-declaration validator requires **every** `items` node to carry `type: "array"` (or a concrete type). When the gateway flattens the schema to the OpenAPI subset Gemini accepts, `oneOf`/`anyOf` is dropped but the outer `type: "array"` + `items` survive — leaving `items` with no `type`, and the request is rejected with `$type == Type.ARRAY`. Same class as the `enum: [""]` in this issue and the array-without-`items` family (#2784 / #2826 upstream-reporting on the gateway side), but a distinct trigger that survives the 6.7.0 `const`/`enum` fixes. ## Scope Of 309 advertised tools in one session, **32** carry an `items` that is a `oneOf`/`anyOf` union with no `type`: ``` build_call_path, build_reconstruction_obligation_ledger, capture_browser_scenario, capture_electron_scenario, capture_native_ui_scenario, compare_application_versions, compare_artifacts, compare_bundles, compare_functions, correlate_static_and_runtime, find_changed_behavior, import_managed_reconstruction, project_android_application_graph, project_apple_application_graph, project_harmony_application_graph, reconcile_javascript_runtime, trace_application_feature, verify_managed_native_boundaries, ... (32 total) ``` ## Suggestion In the compact input-schema projection, when a node is `type: "array"` and its `items` carries only `oneOf`/`anyOf`, derive a single `type` for `items` from the first branch (`object` when all branches are objects, else `string`) rather than emitting an untyped `items`. `compact` alone does not cover this shape today — consistent with the note in #5067 that the profile cannot guarantee API acceptance. ## Cross-reference Reported on the gateway side too, since a `plainSchema` fallback there would fix every MCP at once rather than REA alone: yetone/magpie#3173.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3192
No description provided.