Skip to content

[Bug] Gemini 3.7 Flash video input fails with 502: routed provider emitted undeclared client tool "get_video_duration" #2458

Closed

Description

@GoldenLoaf24h

Client or integration

OpenAI-compatible Chat Completions / Multi-modal API (/v1/chat/completions)

Area

Tools / MCP / Provider compatibility

Summary

When sending a video payload (video_url with data URI or URL) to google-antigravity/gemini-3.7-flash (or Gemini 2.5/3.1 multimodal endpoints), the upstream Vertex / Antigravity provider internally emits built-in server-side helper function calls (such as get_video_duration, get_video_info, or video_analysis:get_video_info) to inspect video metadata before finishing the turn.

Because these tools are internally generated by Google's multimodal runtime and were not explicitly provided in the client's tools array, OpenCodeX's undeclared tool security guard (declaredToolNames check in src/bridge.ts line 1041-1045 and src/server/responses-undeclared-tool-guard.ts) immediately intercepts and aborts the response with HTTP 502:

502 Bad Gateway
{"error":{"message":"routed provider emitted undeclared client tool \"get_video_duration\"; only request-declared tools may be called","type":"server_error","param":null,"code":"upstream_server_error"}}

Expected: Either internal provider-native multimodal inspection tools (e.g. get_video_duration, get_video_info, video_analysis:*) are recognized as provider-internal and allowed/executed transparently, or bypassed in the client tool name declaration guard.

Reproduction

  1. Route a chat completion request to google-antigravity/gemini-3.7-flash with a video attachment via /v1/chat/completions:
    {
      "model": "google-antigravity/gemini-3.7-flash",
      "messages": [
        {
          "role": "user",
          "content": [
            { "type": "text", "text": "Summarize this video" },
            { "type": "video_url", "video_url": { "url": "data:video/mp4;base64,..." } }
          ]
        }
      ]
    }
  2. Observe HTTP 502 response returned from OpenCodeX proxy:
    {
      "error": {
        "message": "routed provider emitted undeclared client tool \"get_video_duration\"; only request-declared tools may be called",
        "code": "upstream_server_error"
      }
    }

Version

@bitkyc08/[email protected] (also verified in 2.26.0)

Operating system

Windows 11 / Linux (x86_64)

Provider and model

google-antigravity/gemini-3.7-flash

Logs or error output

HTTP/1.1 502 Bad Gateway
Content-Type: application/json

{
  "error": {
    "message": "routed provider emitted undeclared client tool \"get_video_duration\"; only request-declared tools may be called",
    "type": "server_error",
    "param": null,
    "code": "upstream_server_error"
  }
}

Upstream error from Vertex AI / Antigravity streaming bridge:
Vertex AI response truncated upstream before the turn completed (MALFORMED_FUNCTION_CALL / undeclared tool get_video_duration)

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. lidge-jun commented on Aug 23, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 62 / 80

    설명: 이 이슈는 구글 안티그래비티의 제미니 3.7 플래시에 동영상 칸을 넣으면, 제공자가 안에서 get_video_duration 같은 검사 도구를 내는데, 프록시가 그걸 클라이언트가 선언하지 않은 도구로 보고 502 로 죽인다고 한다. 작성자는 채팅 완성 길 /v1/chat/completions 에서 재현했다. 버전은 엔피엠 최신 2.31.0 과 2.26.0 이라고 적었다. 지금 CURRENT dev HEAD 는 35a89903c 이다. 이번 시간에 origin/dev 는 6b0f61f64 에서 여기로 왔다. 새 머지는 2454 콤보 할당량 화면, 2456 오너 백로그 기록 두 개다. package.json 은 2.27.0 이다. src/config.ts 는 3238줄이다. src/runtime 폴더는 지금 HEAD 에 없다. 내가 HEAD 를 열어 보니 가드는 그대로다. 코드 안에 get_video_duration 이름은 없다.

    살아 있는 재현은 이렇다. 모델은 google-antigravity/gemini-3.7-flash 다. 메시지에 글과 동영상 주소, 또는 데이터 유알아이를 같이 넣는다. 업스트림은 동영상 길이를 보기 위해 서버 쪽 도우미를 낸다. 그 이름은 요청의 tools 배열에 없다. 프록시는 502 와 문장 routed provider emitted undeclared client tool get_video_duration 을 돌려준다. 기대는 그 검사 도구를 제공자 안으로 보고 통과시키거나, 투명하게 실행하는 것이다. 업스트림은 말고메드 펑션 콜로 잘리기도 한다고 적혀 있다. 가드 502 와 업스트림 잘림이 겹칠 수 있다.

    지금 HEAD 의 src/bridge.ts 1046줄은 선언 목록이 있으면 사건 이름을 그 집합에서 찾는다. 없으면 502 를 내고 응답을 실패로 닫는다. 같은 파일 1794줄은 채팅 완성 길이다. 이번 재현은 채팅 길이다. src/server/responses-undeclared-tool-guard.ts 는 호스트 선언 종류에 웹 검색, 파일 검색, 엑스 서치, 로컬 셸을 넣는다. 동영상 검사 이름은 없다. 이 가드는 보안이다. 선언하지 않은 클라이언트 도구를 막으려고 만들었다. 이름을 전부 통과시키면 안 된다. 초안 2425 는 엑스에이아이 호스트 엑스 서치를 살리는 다른 길이다. 이번 이슈와 한 기차에 섞지 말 것.

    고침은 좁아야 한다. 제미니와 안티그래비티가 동영상 칸이 있을 때만, 검사 이름 몇 개를 제공자 안으로 본다. 그 이름은 get_video_duration, get_video_info, video_analysis 접두 정도다. 클라이언트에 실행을 넘기지 말 것. 가드를 끄지 말 것. 다른 제공자의 임의 이름은 그대로 502 다. 업스트림이 말고메드로 잘리면 가드만 고쳐도 동영상이 살아나지 않을 수 있다. 그 증거는 따로 남겨 둔다. 2457 대시보드 사이드카 저장과 길이 다르다. 2451 wait 밑줄과도 다르다.

    사용자 길이로는 제미니 동영상 한 번이 502 로 죽어서 62. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. Cursor 정적 카탈로그는 opus-4-8-fast / opus-5-fast. 2334 CursorCredentialRouter 는 여전히 src/providers/cursor-pool.ts 모듈+테스트만 있고 어댑터에 연결되지 않았다. 2332 H2 는 discovery 전용. 2320 overflow + 2342 는 이미 dev. 2188 사이드카는 이미 dev. 2361 __omit__ 는 이미 HEAD 다. 이번 시간 2454 콤보 할당량 화면이 착지했다. combo-stream-preflight.ts 는 src/server/responses 에 171줄로 있다. src/lib/bounded-body.ts 128줄은 이미 죽은 시그널에서 취소 없이 던진다. 2426 코덱스 웹소켓 나가는 크기 가드는 없다. 2451 의 wait 허용 목록은 아직 하이픈이다.

    src/bridge.ts 라인 1046 - 선언 목록에 없는 사건 이름은 502 다. 동영상 검사 이름은 없다
    src/bridge.ts 라인 1794 - 채팅 완성 길의 같은 가드다. 이번 재현은 이 길이다
    src/server/responses-undeclared-tool-guard.ts 라인 23 - 호스트 선언 종류에 엑스 서치는 있고 동영상 검사는 없다
    PR 2425 - 엑스에이아이 호스트 엑스 서치 초안이다. 이번 동영상 길과 섞지 말 것
    이슈 2457 - 대시보드 제미니 웹검색 저장이다. 이번 동영상 502 가 아니다

    메인테이너의 판단이 필요한 지점

    • 검사 이름을 제공자 안으로 볼지, 서버가 실행할지. 클라이언트에 넘기지 말 것
    • 가드를 넓힐지. 전체를 끄면 안 된다. 제미니 동영상 칸이 있을 때만 좁게 둔다
    • 업스트림 말고메드 잘림을 이 이슈에 넣을지. 지금은 가드 502 만 잠근다
    • 2425 와 한 기차에 섞지 말 것. 호스트 도구 종류가 다르다

    너의 추천
    이슈는 열어 둔다. 가드를 끄지 말 것. 제미니와 안티그래비티의 동영상 검사 이름만 좁게 통과시킨다. 클라이언트 실행으로 바꾸지 말 것. 2425 와 2457 과 2451 은 닫지 않는다. 호출 길을 넓히지 말 것. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

    이 댓글은 grok-bot이 작성했습니다

  2. lidge-jun commented on Aug 25, 2026

    @lidge-jun
    Owner

    Fixed on dev by #2634 (squash 6ccb13cc6).

    The 502 had a cause one layer earlier than it looked. Chat Completions was silently discarding video_url (src/chat/inbound.ts:56), so the video never reached Gemini at all. The model then called get_video_duration — reasoning about a video it had not been given — and the bridge rejected that undeclared tool call as a local 502. So OpenCodex was refusing a symptom of its own dropped input, which is why the error pointed at the tool call rather than the missing media.

    input_video now flows as a typed part through Chat translation, Responses parsing, request types and admission accounting, and Gemini receives inline video in the shape its API documents: inline_data: { mime_type, data }, the same Part union images use.

    Two limits worth stating rather than leaving you to discover:

    • Remote HTTP video URLs are not forwarded. Gemini's fileData refers to uploaded files, so labeling an arbitrary URL that way would be a claim the API rejects. They become a short text marker. Real remote-URL support needs upload ownership and an SSRF policy — a feature, not part of this fix. Data-URL video works.
    • gemini-3.7-flash stays catalogued as text,image. Codex's catalog modality enum accepts only text/image/audio; adding video invalidates the catalog rather than enabling transport. So video transport works while the advertisement cannot follow until upstream widens the enum.

    Falsified: reverting the Chat translation makes the inline-video test receive only the text part, and the URL case fails outright — 0 pass / 2 fail. Not verified against a live credential-bearing Gemini call; the wire shape is checked against Google's documented Part union.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions