Stream ended: credit lease expired or session_timeout in your console, you’re hitting the per-stream duration limit.
This is expected — each stream has a maximum lifetime, but your application can start a new one immediately to keep going.
Two separate time limits
There are two clocks running independently during an interactive session:
The per-stream limit is the one most people hit first.
It applies to every stream individually, regardless of how much total usage your account allows.
Your account’s total usage quota controls how many hours you can stream overall.
The per-stream limit is separate — each individual stream maxes out at 150 seconds before you need to start the next one.
What the error looks like
When a stream hits its duration limit, the server sends a stream error with reasonsession_timeout.
In your browser console, you’ll see something like:
onStreamError (JavaScript) or on_stream_error (Python) callback.
The stream is done, but the fix is straightforward: start a new one.
Automatically restarting streams
The cleanest way to handle this is to catch thesession_timeout error and reconnect.
After a lease expiry, the server closes the underlying connection, so you’ll need to call connect() again before starting the next stream.
Here’s the pattern for both SDKs:
React example
If you’re building with React, you can wrap the reconnect logic in a hook:Zero-downtime streaming with dual-session rollover
The reconnect patterns above work well, but there’s a visible gap while the new connection spins up. If you need truly seamless, uninterrupted video — for a live demo, a kiosk, or a production experience — you can eliminate the gap entirely by running two client instances and rolling over between them. The idea is simple: you know each stream lasts 150 seconds, so around the 130-second mark, you start warming up a second connection in the background. When it’s ready, you swap the video source and let the first connection wind down. The user never sees an interruption.- It uses two concurrent session slots. Make sure your account’s concurrent session limit can accommodate this.
- The prompt stays the same across rollovers, so the visual output picks up naturally. If your application changes prompts via
interact(), make sure both clients stay in sync. - The 20-second lead time is generous — connection setup usually takes 2-5 seconds, but the extra buffer accounts for cold starts and network variability. Tune this for your environment.
Things to keep in mind
- Always wire up
onStreamError/on_stream_error. Without it, your video feed goes dead when the stream expires and the user has no idea what happened. - Hold onto the current prompt. When you start the next stream, pass the same prompt so the visual picks up where it left off.
- Add a short delay before reconnecting (200–500ms is plenty) in the single-session pattern. This avoids slamming the server if something goes wrong and the error fires in a tight loop.
- Show the user something during the gap if you’re using the single-session pattern. A brief spinner or “Restarting stream…” message goes a long way compared to a frozen or black frame.
Related
Connection vs. Stream
How connections and streams relate to each other.
Session Management
Managing session lifecycle, cleanup, and concurrent limits.