delightful-planet-44653
12/23/2025, 2:08 PMgo-jose/go-jose/jwt: validation failed, token is expired (exp)
What do these mean?tall-airline-16756
12/23/2025, 2:08 PMtall-airline-16756
12/23/2025, 2:08 PMgo-jose/go-jose/jwt: validation failed, token is expired (exp) you see on your self‑hosted LiveKit server.
What it means
• A JWT presented to LiveKit failed validation because its exp (expiration) timestamp is in the past. The server rejects expired tokens.
Why this happens
• The client tried to connect or reauthenticate using a token whose exp has already passed.
• LiveKit does automatically refresh tokens for participants that are already connected, so this error usually appears during initial joins or reconnection attempts after a long disconnect when the original token has expired.
How to fix it
• Generate tokens with a longer validity period appropriate for your use case (e.g., 1–24 hours).
• Generate tokens on-demand from your server at the moment a client needs to join rather than distributing long‑precreated tokens.
• When clients reconnect, ensure they request a fresh token from your backend if the previous token may have expired.
If you want, tell me:
• How you currently generate tokens (SDK / custom code and the exp value you set), and
• Whether this happens on initial join, reconnection, or both—
—and I’ll suggest exact changes or code snippets for your setup.
Sources: server-sdk-ruby | livekit/livekit_composite | DeepWiki | server-sdk-kotlin | livekit/livekit_composite | DeepWikidelightful-planet-44653
12/23/2025, 2:11 PMtall-airline-16756
12/23/2025, 2:12 PMexp) occurs when a client or agent connects to the LiveKit server. If that token is expired, you’ll see errors like token is expired (exp).
• Dispatching an agent (creating a job) simply assigns work to an agent worker. It does not create tokens or extend existing tokens.
Where tokens come from in self‑hosted setups
• Tokens must be generated externally (your backend, CLI tools like lk, or SDK helper code) using your API key/secret or environment variables (LIVEKIT_API_KEY, LIVEKIT_API_SECRET). If you aren’t writing token code, a tool or startup script likely generates them for you.
• Agent processes must present a valid token when registering/connecting. If that token is expired, the agent can’t accept dispatches.
What to check / next steps
• Inspect how your agents start (startup scripts, container command, or CLI) and verify whether tokens are being generated and what exp they contain.
• Check environment variables (LIVEKIT_API_KEY, LIVEKIT_API_SECRET) or any automation that calls lk or SDK token helpers.
• If agents are failing to register or accept jobs, regenerate tokens with a longer validity or ensure your startup flow requests fresh tokens at launch.
If you want, tell me:
• How your agents are launched (CLI, container, or managed service), and
• Any startup commands or env vars you see —
and I’ll point to the exact places to check or suggest the token-generation change you should make.
Sources: Agent dispatch | LiveKit docs | Agents Framework | livekit/livekit_composite | DeepWiki | server-sdk-ruby | livekit/livekit_composite | DeepWiki | livekit/livekit_composite | DeepWiki | server-sdk-js | livekit/livekit_composite | DeepWikidelightful-planet-44653
12/23/2025, 2:23 PMtall-airline-16756
12/23/2025, 2:23 PMservice/utils.go:54 showing:
"invalid token: ... error: go-jose/go-jose/jwt: validation failed, token is expired (exp)"
What this log means
• LiveKit rejected an incoming RTC request (HTTP GET /rtc) because the JWT presented had an exp timestamp that is already past. That is why you see status 401 and the "token is expired (exp)" message.
Quick checklist to resolve it
• Confirm how the token is being created: CLI (lk), SDK helper, container startup script, or environment-derived (`LIVEKIT_API_KEY`/`LIVEKIT_API_SECRET`). If you didn’t write token code, a tool is generating it for you.
• Check the token’s exp value (decode the JWT at jwt.io or with jwt tooling) to see when it was issued and when it expires.
• Ensure system clocks are accurate on client/agent machines and the LiveKit server (clock skew can make valid tokens appear expired).
• If tokens are short-lived, switch to generating tokens on-demand at client/agent startup or increase token TTL (e.g., 1–24 hours depending on your needs).
• For agents: verify they present fresh tokens when registering; if they reuse a precreated token that has expired, they’ll fail to connect and dispatch will be impacted.
If you want, provide:
• How agents/clients are started (container command, CLI, or script) and
• The decoded iat and exp timestamps from one of the failing tokens
—I’ll point to the exact file/command to update and give a token-generation snippet matching your setup.delightful-planet-44653
12/23/2025, 2:26 PMasync with lk_api.LiveKitAPI(
url=self.livekit_url,
api_key=self.livekit_api_key,
api_secret=self.livekit_api_secret,
) as client:
dispatch = await client.agent_dispatch.create_dispatch(
lk_api.CreateAgentDispatchRequest(
agent_name="outbound-caller",
room=room_name,
metadata=tara_livekit_req.model_dump_json(),
)
)
[[package]]
name = "livekit-api"
version = "1.0.4"tall-airline-16756
12/23/2025, 2:27 PMuv run agent.py start, dispatch created with the Python livekit-api client) and the log showing the expired token.
Short answer: the expired token is on the agent side, not created by the dispatch call. Your dispatch just queues work for `agent_name="outbound-caller"`; an agent worker must connect with a valid JWT containing that agent_name to receive jobs. If the worker’s token is expired, it never registers and won’t get the dispatch.
What to check and do next
• Confirm your agent startup path (in agent.py) generates or fetches a fresh JWT at runtime using `LIVEKIT_API_KEY`/`LIVEKIT_API_SECRET`. If it uses a precreated token, replace that with runtime generation.
• Decode a failing token (jwt.io or a small script) and inspect iat and exp to confirm it’s expired and to see TTL.
• Verify system clock on agent host and LiveKit server (clock skew can cause valid tokens to appear expired).
• Ensure the token includes the agent grant/option matching agent_name="outbound-caller".
If you want, paste the relevant part of agent.py (the auth/connection code) or show how you set env vars/CLI for the agent. I’ll point out exactly where to generate a fresh token and provide a minimal code snippet to do it.
Sources: Agents Framework | livekit/livekit_composite | DeepWiki | server-sdk-ruby | livekit/livekit_composite | DeepWiki | Outbound Calling Script | LiveKit docsdelightful-planet-44653
12/23/2025, 2:29 PMasync def entrypoint(ctx: JobContext):
# job handling code
if __name__ == "__main__":
cli.run_app(
WorkerOptions(
api_key=settings.livekit_api_key,
api_secret=settings.livekit_api_secret,
ws_url=settings.livekit_url,
entrypoint_fnc=entrypoint,
agent_name=settings.agent_name,
request_fnc=request_fnc,
drain_timeout=drain_timeout,
shutdown_process_timeout=shutdown_process_timeout,
load_fnc=calc_and_record_load,
load_threshold=settings.worker_load_threshold or 0.7,
)
)tall-airline-16756
12/23/2025, 2:30 PMagent.py snippet and the failing logs.
Everything looks correct: passing `api_key`/`api_secret` into WorkerOptions tells the agent runtime to generate a token for itself. The error means that the token the agent runtime produced (or loaded) is expired at connect time, so the agent never authenticates and therefore never receives dispatches.
What to do next
• Confirm the agent runtime is generating a fresh token on startup (not reusing a precreated token file). If it is reusing a token, change it to generate a new one each start.
• If the runtime generates tokens automatically, ensure the generated TTL is long enough. Two options:
◦ Preferred: generate the token yourself and pass it into WorkerOptions(token=...) with an explicit TTL (e.g., 24h).
◦ Alternative: set an env var like LIVEKIT_TOKEN_TTL=86400 if your runtime honors it.
• Decode one failing token (jwt.io or a small script) and check iat and exp to confirm expiry and TTL.
• Verify clocks (NTP) on agent host and LiveKit server to rule out clock skew.
If you want, paste the agent runtime auth/connection snippet (or I can show a minimal Python snippet) and I’ll give the exact code to generate a long-lived token and how to pass it into WorkerOptions.
Sources: Agent dispatch | LiveKit docs | server-sdk-kotlin | livekit/livekit_composite | DeepWiki | server-sdk-ruby | livekit/livekit_composite | DeepWiki | server-sdk-go | livekit/livekit_composite | DeepWiki