---
title: "Timeouts and long requests"
description: "pirouter waits up to 600 seconds for a provider to start answering and returns 200 with a keepalive every 20 seconds once the provider has been silent for 90 seconds, so set client timeouts above 600 seconds and check the body for an error."
canonical: "https://pirouter.ai/docs/guides/timeouts"
last-updated: "2026-10-17"
lang: "en"
source: "content/docs/en/guides/timeouts.mdx"
---

# Timeouts and long requests

pirouter waits up to 600 seconds for a provider to start answering and returns 200 with a keepalive every 20 seconds once the provider has been silent for 90 seconds, so set client timeouts above 600 seconds and check the body for an error.

pirouter waits up to 600 seconds for a provider to start answering. When a provider has been silent for 90 seconds, the gateway answers `200` first and sends keepalives so that nothing in between closes the connection. Set your client timeout above 600 seconds.

## Timeouts

pirouter waits up to 600 seconds for the provider to start answering, streamed or not. A response that is not streamed starts when the whole answer is ready, so for it the 600 seconds cover the whole answer. A streamed response has no limit on its total duration once its first event has arrived.

A provider that is silent for longer than 90 seconds is handled as a [long request](https://pirouter.ai/docs/guides/timeouts.md#long-requests): the response starts with status `200`, so a timeout after that arrives as an error in the body or in the stream, with `upstream_timeout` as `error.code` and `gateway_timeout` as `error.type`. Retry a timeout.

Set your client's timeout above 600 seconds. A client that counts only the time between bytes needs more than 90 seconds, because the first byte can take that long. A shorter timeout gives up on requests the gateway would still have answered.

## Long requests

Some requests take minutes before the provider sends anything: images at high quality, or models that reason at length before a long answer. To keep the connection open meanwhile, pirouter starts the response itself once the provider has been silent for 90 seconds. It sends status `200`, then keeps the connection alive every 20 seconds in the format of the response:

- **Not streamed**: `Content-Type: application/json` and one space each time. JSON allows whitespace before a value, so SDKs and JSON parsers read the body as usual when it arrives.
- **Streamed**: `Content-Type: text/event-stream` and one comment line, `: keepalive`, each time. SSE clients ignore comment lines. When the provider starts answering, its events follow as usual.

Send Gemini `streamGenerateContent` requests with `alt=sse`. Without it, pirouter treats the request as not streamed and keeps it alive with spaces instead of `: keepalive` comments. A request whose provider answers within 90 seconds is not affected.

> **Warning:** A long request that fails still has status `200`, so a client that reads only the status takes the failure for a success. Check a non-streamed body for a top-level `error` key, and a stream for an `error` event.

Three things differ on these responses:

- **A failure arrives with status `200`.** The status was sent before the provider answered. A failure after that point is a body with a top-level `error` key when the response is not streamed, and one `error` event whose data is the error object when it is streamed. The error is the provider's own, or the pirouter error, such as `upstream_timeout` when 600 seconds pass with no answer.
- **Only `X-Pi-Trace-Id` is set.** The headers left before any provider answered, so `X-Pi-Provider`, `X-Pi-Model` and `X-Pi-Upstream-*` are absent. Quote the trace ID when you report a problem.
- **No retry on another provider after 90 seconds.** pirouter tries other providers and [fallback models](https://pirouter.ai/docs/guides/fallbacks.md) only before the response starts.

A streamed request that times out after its keepalives looks like this:

```text
: keepalive

: keepalive

event: error
data: {"error":{"message":"The upstream did not start responding within the time limit.","type":"gateway_timeout","code":"upstream_timeout"}}
```

## Next steps

- [Errors](https://pirouter.ai/docs/api/errors.md): What each error code means, and which errors to retry.
- [Generate and edit images](https://pirouter.ai/docs/guides/images.md): High-quality images often take longer than 90 seconds and become long requests.
