SynapseWire

The Blog Says One Hour. SSE Still Defaults to 15.

API Gateway streaming is in public preview. The blog caps a stream at one hour. SSE still defaults to a 15-second deadline unless you set one.

Published on:
A closed laptop, a paper kitchen timer, and a blank index card on a wooden desk under a warm lamp.
FIG. 01 // A closed laptop, a paper kitchen timer, and a blank index card on a wooden desk under a warm lamp.

The announcement and the deadline table are not describing the same default. Google’s October 22 post says streams can stay open for up to one hour. The streaming configuration page says the deadline on an SSE or chunked-transfer path still defaults to 15 seconds, and that turning streaming on does not change that. One hour is 3,600 seconds. It is the maximum. It is not what you get if you only create the gateway.

We have already watched a socket example and a model card disagree on the string. Grok Voice’s query parameter is an alias if the secondary page is right. We have already watched a knowledge API want a search before a dump. Search the chunks first. We have already watched a sticker that was not the bill. Haiku 5.5 lists at $0.10. API Gateway’s hour is the same shape of mistake: a ceiling written as if it were the setting.

Fifteen seconds is still the SSE bound

The docs are blunt about what the flag does not do. Enabling streaming on a gateway does not change how the deadline field behaves on an SSE or chunked-transfer path. The deadline remains a wall-clock bound on the complete response. A stream is cut once the deadline elapses, regardless of how much data it is still sending. The default is 15 seconds. The maximum is 3,600 seconds.

That is the sentence to put in the runbook above the blog quote. A client that opens an SSE chat completion and then waits on a slow first token will die at 15 seconds on a streaming-enabled gateway that never set deadline. The preview did not move the default. It raised the ceiling, and only for gateways created with streaming on. A non-streaming gateway’s deadline tops out at the old limit. The table says the 3,600-second maximum applies to streaming-enabled gateways. Creating the new gateway is the precondition. Setting deadline is the second step. The blog’s “up to one hour” describes the result of both steps, not the result of reading the post.

The idle column is where people talk themselves into skipping the deadline. For HTTP streaming, SSE and chunked transfer, the idle timeout is marked N/A: effectively infinite. Only the request timeout ends the stream. Infinite idle does not mean infinite life. A stream that emits a token every second still dies when the wall clock hits deadline. A stream that emits nothing for 40 seconds also dies at 15 seconds if you left the default, but it dies because the request timer expired, not because an idle timer fired. There is no idle timer on that row. Debugging “idle timeout” in the logs will send you looking for a knob the SSE row does not have.

WebSockets and gRPC are a different row, and folding them into the SSE sentence is how a config review approves the wrong number. Idle timeout for streaming over gRPC or WebSockets defaults to 300 seconds. You can set deadline to change it, up to 3,600 seconds on a streaming-enabled gateway. On WebSockets, a deadline below 300 seconds is ignored, and a 300-second minimum applies. The request timeout on that row is always 3,600 seconds for streaming-enabled gateways, and it is not configurable. A WebSocket can be killed by a 300-second gap between messages even while the connection-level cap is an hour. A deadline: 30 copied from an HTTP habit will not give you a 30-second WebSocket gap. The docs say that value is ignored and the minimum is 300. If you needed a short WebSocket, this preview does not offer that knob.

Non-streaming requests stay on the 15-second default too. The table’s first row: idle N/A, request timeout default 15 seconds, deadline up to 3,600 only on streaming-enabled gateways. Turning the flag on does not silently lengthen your unary calls. It allows you to lengthen them. A health check that used to rely on the 15-second default still has it, unless someone set a backend deadline of 3600.0 for the chat route and attached that backend to the health route by mistake.

The flag is creation-time, and MCP does not inherit it

Streaming is specified when the gateway is created. The limitation that matters in production is immutability. You cannot update an existing gateway to enable or disable streaming. You create a new gateway. The streaming-enabled gateway receives a different hostname shape, so clients or DNS records have to move. The docs mention hostname patterns and a support path if you want an existing record rewritten to the new format. The pattern strings themselves did not survive cleanly in the section I could quote. Read that heading before you cut a DNS change. What is clear is that the hostname changes shape, and that a client still pointed at the old gateway will not grow streaming because you updated a spec.

The blog’s get-started line matches the immutability rule, if you read it as “new.” “Point a new streaming-enabled gateway at an existing backend that emits SSE.” New gateway. Existing backend. The spec, the blog says, does not have to change. That can be true and still leave you with a 15-second stream, because “no spec changes” and “set deadline to 3600” are different claims. No new extension is required to describe the streaming operation. A deadline field is how you spend the hour the blog advertised. If your current spec has no deadline, the new gateway will apply the default.

MCP is the exception that will waste an afternoon. Creating the gateway with --enable-streaming does not make an MCP endpoint stream. MCP responses remain a single application/json body regardless of the gateway’s streaming mode. The docs point at MCP Limitations for the rest. If your agent protocol is MCP, the preview flag is not the switch that chunks the body. SSE, chunked HTTP, WebSockets, and gRPC streaming are the patterns the blog lists. MCP is called out on the docs page as still one JSON body. Test the content type. If the response is application/json and the client is waiting on event-stream frames, the flag is a red herring.

Protocol is a second field people skip because the examples look finished. The OpenAPI 2.0 snippet sets protocol: h2 next to deadline: 3600.0 under x-google-backend. A separate note says to use http/1.1 for WebSockets. Copying the h2 example onto a WebSocket backend is not what that note says. OpenAPI 3.x puts the same pair, protocol h2 and deadline 3600.0, under x-google-api-management backends, then points x-google-backend at the named backend. The 3600.0 in the example is a choice. It is the maximum, written out. It is not inserted for you when the gateway is streaming-enabled.

Path translation has a default that will move your URL even when the deadline is right. A top-level x-google-backend defaults to pathTranslation: APPEND_PATH_TO_ADDRESS. The gateway appends the request path to the backend address, so a request to /v1/chat/completions reaches a backend that actually has that path. If your backend expects the path at the root, the append will 404 a stream that would otherwise have stayed open. That failure looks like a streaming bug. It is a path bug. The docs use it as the reason a Gemma-style backend receives /v1/chat/completions. Match the backend or set the translation. Do not raise the deadline to debug a 404.

570 and 600, and whose timer fires

The docs walk through a concrete clash, and it is the useful one. The deadline of 570 seconds is 30 seconds shorter than the --timeout 600 that the Gemma guide sets on the service. The gateway’s deadline, not the service timeout, ends a stream that runs too long. Two timers, the shorter one wins, and the shorter one in that example is the gateway.

If you set deadline: 3600 because the blog said one hour, and the process behind the gateway still has a 600-second timeout, the process wins. The client will see the stream die at 10 minutes and the blog will look wrong. The blog was describing the gateway cap. The process has its own. Write both numbers down before you pick 3600.0. A 570/600 pair is the docs telling you they already thought about this once, for Gemma. Your vLLM, your reverse proxy, and your load balancer each get a vote. The gateway will not outlive a proxy that closes at 60 seconds. Idle “infinite” on the SSE row does not poke a hole in that proxy.

Authentication in the same example is a Google-signed ID token with the audience gemma-api. The docs say you can choose a different audience string as long as callers request the same one when they mint the token. The audience is not a streaming setting. A 401 is not a deadline. A stream that never starts because the token audience does not match will be described, in a postmortem, as “streaming failed in preview.” Check the status code before you touch deadline. The security requirement makes the gateway reject any request that does not carry that token. Rejection is a response. It is not a truncated stream.

The blog’s model-routing sentence is easy to over-read. A gateway that uses model routing now streams responses from Gemini, Claude, and OpenAI gpt-oss models in model garden as they are generated, and streaming backends you host anywhere else work the same way. “The same way” means the gateway will pass the stream through. It does not mean those models ignore the 15-second default. It does not mean gpt-oss and Claude share a timeout. It means the preview is not limited to one vendor’s chunked format. SSE is called the de facto standard for streaming model output to a browser or SDK, and the transport behind most OpenAI-compatible chat completion APIs. Chunked transfer and NDJSON are passed through as the backend produces them, rather than buffered to the end. WebSockets are full duplex. gRPC streaming, server-side and bidirectional, is why a gateway can sit in front of services that previously could not be proxied here. Those are four patterns. They do not share the WebSocket idle row. SSE is the HTTP row. gRPC is the 300-second row.

Reconnection is the blog’s other operational sentence, and it is the one the deadline table makes urgent. Clients should implement reconnection so a session survives the end of a stream. A well-behaved WebSocket or SSE client should be doing this anyway. On a default SSE gateway, “the end of a stream” can be 15 seconds into a long completion. Reconnection that assumes the only cut is the one-hour cap will treat a default deadline as a network fault and retry in a loop. Distinguish a deadline cut from a disconnect if your client library exposes it. If it does not, log the elapsed time. Fifteen seconds on the nose is the default. Three thousand six hundred seconds on the nose is the cap. Anything else is something in between that you set, or something in front of the gateway that you forgot.

What to put in the spec, in order

Create a new gateway with streaming enabled. The flag the MCP limitation names is --enable-streaming. Do not plan to flip it on the gateway that already has your DNS name. Plan a new hostname, then move clients.

Point that gateway at the backend that already emits SSE, or chunked JSON, or the gRPC stream you mean to expose. Leave MCP on its own route if MCP has to stay a single JSON body. Do not expect the flag to change that content type.

Set deadline on the backend definition you actually want to last. For an SSE chat route, 3600.0 is the blog’s ceiling, written as a number the docs accept. A smaller number is fine if your model calls are shorter and you would rather fail fast. 15 is what you already have if you set nothing. For WebSockets, do not bother with a deadline under 300. The docs say it is ignored. Use protocol: http/1.1 for that WebSocket backend, not the h2 example, unless you have read a newer note than the one I used.

Set the process timeout longer than the gateway deadline if you want the gateway to be the component that ends the stream. The 570 versus 600 example is the pattern: gateway first, service thirty seconds later, so the cut you debug is the one you configured. If a proxy in the middle closes sooner, fix the proxy or stop advertising the hour.

Keep the OpenAPI document you already have if it already describes the route. The blog’s claim is that streaming is not a new resource type and not a new annotation. That claim survived contact with the docs, with one addition: the deadline field is how the hour becomes a configuration instead of a headline. Audience, path translation, and protocol were already fields. They still cut streams, just not with a timer.

Public preview is the label on both pages. Preview means the hostname shape, the immutability, and the MCP exception are in the limitation list on purpose. I would not migrate the only gateway in front of a customer chat on the afternoon you read the post. I would stand up the new gateway, set a deadline you can recognize in the logs, and send one SSE request that you expect to last longer than 15 seconds. If it dies at 15, the flag is on and the field is missing. If it dies at the deadline you set, you are on the page the blog was summarizing. The summary left the default out.

Share Article //
READER LETTERS

Reader Dispatches

[ 0 Responses ]

No reader responses yet. Share your technical perspective below.

FURTHER READING

Related Posts