Gemini Omni audio is always on: generate_audio false returns 400

Sume's Omni row rejects generate_audio false with a 400 because audio is native and always on. To ship a silent clip, drop the track with video-trim after.

4 min readSume
All posts

You cannot turn audio off on Gemini Omni through Sume: generate_audio: false returns a 400, because the model always produces native synced audio. If you need a silent clip, generate normally and then remove the track with Sume's video-trim using audio: "drop".

Why the 400

Sume's Video Router doc lists three Omni inputs that fail with 400: generate_audio: false, bitrate_mode and reference_audio_urls. The same rule holds under sume/auto, which defaults to Omni, so a request that sends generate_audio: false fails there too and is never silently routed to another model. Google's own Veo page says audio is always on for all Veo 3.1 models, so the behaviour is the same on both families.

Audio behaviour by surface (read 2026-10-05)
SurfaceAudio toggleSource
Veo 3.1, 3.1 Fast, LiteAlways onGoogle Veo guide
Gemini Omni on Sumegenerate_audio false is a 400Sume Video Router docs
sume/autogenerate_audio false failsSume Videos API contract
Other Sume catalog rowsDiffers by rowSume catalog capabilities

Steer audio with words instead

Google's API guide says to describe audio explicitly, for example "Include calm background music", and to use timing words such as "After 3 seconds, a woman enters". If you do not want music, say "no music, only room tone". That does not guarantee silence, but it removes the track you were worried about.

Catch the 400 in your client

The script below sends the invalid flag on purpose and prints the public error, so you can see the exact code your retry logic must not retry.

import os, requests

r = requests.post(
    "https://api.sume.com/v1/videos",
    json={"model": "gemini-omni-flash-1.1", "prompt": "A paper boat on a puddle",
          "duration": 4, "generate_audio": False},
    headers={"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
             "Idempotency-Key": "omni-audio-off-test"},
    timeout=60,
)
print(r.status_code)
err = r.json().get("error", {})
print(err.get("code"), err.get("message"))
if r.status_code == 400:
    print("Do not retry; remove generate_audio or pick another model.")

Dropping the track after the fact

Video trim takes a media.sume.com clip of your workspace, a start, and one of end or duration, and its audio field is keep by default or drop. Send audio: "drop" and you get a new MP4 with no sound for $0.02, and the source is untouched. Exact precision re-encodes the video, so check the result before you publish. Other catalog rows differ, so read capabilities for the model you use before you assume a toggle exists.

What not to do

Treating the 400 as a configuration signal, not as a flaky error, keeps retry budgets for the cases that deserve them, such as 429 queue_full.

  • Do not retry the 400 with the same body, because it will fail the same way.
  • Do not switch to sume/auto to get around it, because auto fails closed on the same flag and never silently reroutes.
  • Do not publish before you listen: a trimmed clip with the track dropped should be played end to end once.
  • Do not forget that bitrate_mode and reference_audio_urls are also 400s on this model.

Errors in the docs

A 400 is not retryable; fix the body. See Errors and credits for the full status table and the rule about retrying only with the same Idempotency-Key.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume