Ephemeral token resumption consumes uses even with uses=1 (Live API v1alpha)

,

Hi team,

I’m testing ephemeral token + Live session resumption exactly as
described in the docs, to verify that resumption does not consume uses
when uses=1.
However, the actual behavior contradicts the documentation, so I’m
reporting it here.

———

What I want to do
Per docs, within expireTime, I should be able to reconnect using
sessionResumption with the same token even if uses: 1, and resumption
should not count as a use.

———

Expected

  • First session opens normally
  • Receive sessionResumptionUpdate with resumable=true and a valid
    newHandle
  • Close the first session (code 1000)
  • Reconnect immediately with the same token + handle
  • Reconnect succeeds and does not fail with “Token has been used too many
    times”

———

Actual

  • I do receive a valid handle (resumable=true, newHandle present)
  • First session closes cleanly (code 1000)
  • Reconnect immediately with the same token + handle
  • Reconnect fails with Token has been used too many times (code 1011)

———

Environment

  • OS: macOS 15.6 (24G84)
  • Browser: Arc(Chromium Engine Version 144.0.7559.60)/ Chrome (144.0.7559.97 (arm64))
  • Node: v22.18.0
  • SDK: @google/genai 1.35.0
  • Model: gemini-2.5-flash-native-audio-preview-12-2025
  • Date: 2026‑01‑23

———

Log excerpt (redacted)

[first] sessionResumptionUpdate resumable=true hasHandle=true
[first] Close: code=1000 reason=
[reconnect] Opened
[reconnect] Close: code=1011 reason=Token has been used too many times

———

Repro code

(see below)

Additional note:

  • Live session resumption using a regular API key (non‑ephemeral) works
    as expected.
  • The failure only occurs with ephemeral tokens when uses=1.
 // app/api/gemini/debug-token/route.ts
 /**
  * Debug-only endpoint to create an ephemeral token for client-side
 repro.
  * This route is disabled in production.
  */
 export const dynamic = 'force-dynamic';

 import { NextResponse } from 'next/server';
 import { GoogleGenAI, Modality } from '@google/genai';
 import { serverEnv } from '@/lib/config/server';
 import { LIVE_API_MODEL } from '@/lib/gemini/types';

 type DebugTokenRequest = {
   uses?: number;
   model?: string;
   expireMinutes?: number;
   newSessionExpireMinutes?: number;
 };

 export async function POST(request: Request) {
   if (serverEnv.nodeEnv === 'production') {
     return NextResponse.json({ error: 'Not found' }, { status: 404 });
   }

   const apiKey = serverEnv.geminiApiKey;
   if (!apiKey) {
     return NextResponse.json({ error: 'GEMINI_API_KEY not configured' },
 { status: 400 });
   }

   let body: DebugTokenRequest = {};
   try {
     body = (await request.json()) as DebugTokenRequest;
   } catch {
     body = {};
   }

   const uses = Number.isFinite(body.uses) ? Math.max(1,
 Math.floor(body.uses as number)) : 1;
   const expireMinutes =
     Number.isFinite(body.expireMinutes) && (body.expireMinutes as number)
 > 0
       ? (body.expireMinutes as number)
       : 30;
   const newSessionExpireMinutes =
     Number.isFinite(body.newSessionExpireMinutes) &&
 (body.newSessionExpireMinutes as number) > 0
       ? (body.newSessionExpireMinutes as number)
       : 1;
   const model = body.model && typeof body.model === 'string' ?
 body.model : LIVE_API_MODEL;

   const client = new GoogleGenAI({ apiKey, httpOptions: { apiVersion:
 'v1alpha' } });
   const expireTime = new Date(Date.now() + expireMinutes * 60 * 1000);
   const newSessionExpireTime = new Date(Date.now() +
 newSessionExpireMinutes * 60 * 1000);

   const tokenResponse = await client.authTokens.create({
     config: {
       uses,
       expireTime: expireTime.toISOString(),
       newSessionExpireTime: newSessionExpireTime.toISOString(),
       httpOptions: { apiVersion: 'v1alpha' },
       liveConnectConstraints: {
         model,
         config: {
           sessionResumption: {},
           temperature: 0.7,
           responseModalities: [Modality.AUDIO],
         },
       },
     },
   });

   return NextResponse.json({
     token: tokenResponse.name || '',
     model,
     uses,
     expireTime: expireTime.toISOString(),
     newSessionExpireTime: newSessionExpireTime.toISOString(),
   });
 }

Hi there! We apologize that the ephemeral token resumption consumes uses even with uses=1. I passed this issue along to our engineering team to debug - we appreciate the detailed description of the issue

1 Like

Hi @Alisa_Fortin

I found another related issue. Even after working around the uses problem by setting uses=5, session resumption with ephemeral tokens does not preserve conversation context.

I’ve created a separate discussion: [link]

Thanks!