On self hosted livekit server, I'm getting errors ...
# ask-ai
d
On self hosted livekit server, I'm getting errors like
Copy code
go-jose/go-jose/jwt: validation failed, token is expired (exp)
What do these mean?
t
Thanks for reaching out, akshat. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding about the error:
go-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 | DeepWiki
d
Not creating tokens through code. Does it happen internally when dispatch requests are created?
t
Thanks — I’m responding to your question about whether token expiration happens internally when dispatch requests are created. Short answer: No — dispatch does not generate or renew tokens internally. What actually happens • Token validation (including checking
exp
) 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 | DeepWiki
d
caller is service/utils.go:54 { "level": "warn", "ts": 1766491935.688471, "logger": "livekit", "caller": "service/utils.go:54", "msg": "*error* handling request", "status": 401, "method": "GET", "path": "/rtc", "*error*": "invalid token: eyJhb ... token value, error: go-jose/go-jose/jwt: validation failed, token is expired (exp)" }
t
Thanks — I’m replying about the log you pasted from
service/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.
d
The agents code is pretty simple and is run using uv run agent.py start The entrypoint function takes in the job request and handles but the agent itself didn't receive any requests. The dispatch requests are created from another service like this
Copy code
async 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(),
        )
    )
Copy code
[[package]]
name = "livekit-api"
version = "1.0.4"
t
Thanks — I’m responding to your latest details (agent started via
uv 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 docs
d
Here's the relevant part for agents
Copy code
async 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,
        )
    )
t
Thanks — responding to your
agent.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