The rtc/v1/validate?access_token API is returning ...
# ask-ai
c
The rtc/v1/validate?access_token API is returning cannot unmarshal wrapped join request Error, when incoming from web sdk. I'm using livekit cloud.
✅ 1
t
Thanks for reaching out, Bharath. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m sorry you’re hitting this error. I’m responding about the “cannot unmarshal wrapped join request” returned by
rtc/v1/validate?access_token
when joining from the web SDK. I don’t have enough detail yet to pinpoint the cause. Could you share the following so I can diagnose quickly? • SDK version you’re using (web SDK package and exact version). • How you generate the access token (server code snippet or method, and whether you’re using JWT or the LiveKit server SDK). • The exact HTTP request to
rtc/v1/validate?access_token
(headers and body). If you can’t share secrets, redact the token but keep the request shape. • Any server logs where the token is created and any client console logs when calling `connect`/`join`. • Whether this happens for all browsers/clients or only one. Possible causes to check while you gather that: • Token payload is double-wrapped or encoded incorrectly (for example, a JSON string containing another JSON instead of a proper JWT). • Using the wrong token type (a RoomJoin request expected but an incorrectly formatted payload sent). • Mismatch between how the token is generated and what the cloud
validate
endpoint expects (e.g., different SDKs/versions). If you share the requested details (redacting secrets), I’ll look for the exact mismatch and give concrete steps to fix it. , with interactive elements
Thanks — I’m responding about the curl you just shared and the “cannot unmarshal wrapped join request” error from
rtc/v1/validate
. From the request shape, the root cause is very likely a malformed
join_request
value (double‑encoded, padded incorrectly, or not the expected Base64‑URL‑encoded protobuf/JSON that LiveKit expects). To diagnose quickly I need two small pieces: 1. The web SDK version you’re using (exact package and version). 2. The code that generates the
join_request
(or the server function that creates it). Redact secrets but keep the exact encoding steps and any Base64 calls. While you gather that, check these likely issues: •
join_request
should be Base64‑URL encoded (no + or /, use - and _, and no padding) of the expected join payload. Standard Base64 or a JSON string wrapped inside another encoding will fail to unmarshal. • Ensure you are not double‑encoding (encoding JSON into a string then encoding that string again). • Confirm you’re sending the
join_request
exactly as produced (no URL-encoding differences or truncation by client code). If you paste the token-generation/join_request creation snippet (redacted token values OK), I’ll point out exactly what to change. , with interactive elements
c
In some of the web calls, the v1/validate API is being called and in some scenarios it's not. why is there a variation?
t
Thanks — I’m responding about why
rtc/v1/validate
is called in some web SDK cases but not others. Short answer: the web SDK only calls the
validate
endpoint when it needs to confirm or exchange a join token — it won’t call it for every join. Variation typically comes from differences in how the client is authenticating or how the token is provided. Common reasons you’ll see the call in some flows but not others: • Token vs. token-less flows: If the client provides a full usable join token directly, the SDK can connect without extra validation. If the client provides a short-lived/partial token or uses a token-exchange flow, the SDK calls
rtc/v1/validate
to verify or exchange it. • Different SDK versions or build configs: Older/newer SDKs may change when validation happens. • Differences in how you generate/send the token: e.g., if some clients send a prebuilt join_request and others send a wrapped/encoded payload, the SDK may call validate to unwrap/confirm it. • Client logic or custom wrappers: some app code may request validation explicitly (or manipulate the token) before calling
connect
. To pinpoint why you see variation in your case, please tell me: • The web SDK version(s) in use. • One example of a call that triggers
validate
and one that doesn’t (request shape or client code around
connect
). Redact secrets. • How you generate and supply tokens to clients (server snippet or description). With those details I’ll identify which flow your clients are using and recommend the minimal change to make behavior consistent. , with interactive elements
c
I'm using web sdk version 2.19.0 and the join_request param is being generated by the sdk itself which is being double encoded
t
Thanks — I’m responding to your note that you’re on web SDK v2.19.0 and the SDK is double‑encoding the
join_request
, causing the error and inconsistent
rtc/v1/validate
calls. What’s happening • Double‑encoding the
join_request
prevents the server from decoding the expected protobuf/JSON payload, which causes the "cannot unmarshal wrapped join request" error. • The SDK calls
rtc/v1/validate
only when it needs to exchange or confirm a token (e.g., when it receives a wrapped/partial token rather than a full join token). If the SDK receives a proper, single‑encoded join payload it may skip the extra validate exchange — that’s why you see variation. How to fix it (quick checklist) 1. Stop encoding the SDK’s
join_request
a second time. Pass the SDK’s generated
join_request
value directly to `connect`/the join flow without additional Base64/json encoding. 2. Ensure the
join_request
uses Base64‑URL encoding (no + or /, use - and _, and no padding) if you are encoding it manually. Do not wrap JSON as a string then encode again. 3. Confirm the client sends exactly the SDK output (redact tokens) — no extra URL-encoding, stringification, or re-encoding by your app code. 4. If you must transform it server-side, decode once, transform, then re-encode only once into the expected Base64‑URL format. If you’d like, paste a redacted example of the
join_request
value before and after your app transforms it (or the small snippet where you modify/forward it). I’ll point out the exact line that’s double‑encoding and show the minimal change. , with interactive elements
c
Does the livekit sdk load different files for US and other locations?
t
I’m responding to your question about whether the LiveKit SDK loads different files for the US versus other locations. The SDK itself does not load different code files per region. Region-specific behavior comes from which LiveKit service endpoint you connect to (the server/cluster URL) rather than different SDK bundles. If you want, tell me the endpoint you’re using and I’ll help confirm it’s the correct regional URL or show how to point clients to a specific region. , with interactive elements
c
I checked my code and the join_request is no where created or transformed in my app. It's all happening within the sdk itself
t
Thanks — I’m responding to your note that your app doesn’t touch
join_request
and the SDK appears to be doing the double‑encoding. You’re correct that the web SDK generates and encodes the
join_request
internally. If your app truly isn’t modifying the token or request, this points to one of two possibilities: • The token you hand the SDK is already encoded/wrapped (URL‑encoded, Base64, or stringified) so the SDK encodes again when building its join payload. • There’s an SDK bug or an interaction with your environment (build, proxy, or middleware) that alters the token before the SDK uses it. Next steps so I can pinpoint the cause: • Please paste the minimal snippet where you call the SDK’s connect/join (redact secrets). Example: the call to
connect(...)
or
join(...)
and how you obtain the token immediately before that call. • Tell me how the token is delivered to the client (direct from your server, via query param, from a CDN, etc.). • Confirm whether you see any middleware, proxy, or URL rewriting between your server and the browser. If you prefer, share a redacted example of the token string as received by the client (the raw token you pass into the SDK). I’ll check for double‑encoding patterns and give the exact line to change or confirm whether this looks like an SDK issue. , with interactive elements
c
When you say token, is it the jwt token that I generate or the join_request that the sdk is generating?
t
Good question — let me clarify. • The JWT token is the server‑generated credential you create (the join token). You generate this on your server and hand it to the client. This is what proves identity/permissions to LiveKit. • The
join_request
is generated by the web SDK internally when it builds the connection request. The SDK wraps/encodes the join token into the
join_request
payload sent to
rtc/v1/validate
. Which to focus on • Start by verifying the JWT you generate is a plain, correctly formed token (no extra encoding or wrapping) when it arrives in the browser. If the JWT is already double‑encoded or wrapped, the SDK will encode again and produce the error. • If the JWT arriving at the client looks correct, the double‑encoding is happening inside the SDK or due to an intermediary (proxy/build step). In that case share the minimal snippet where you call
connect
(redact secrets) and how the token is delivered to the client. If you paste the call to
connect(...)
and the raw JWT as received by the client (redact values), I’ll check for encoding issues and next steps. , with interactive elements
c
The JWT is correctly sent. No issues with JWT. The issue is with the join_request being double encoded
t
Thanks — I’m responding to your confirmation that the JWT is correct and the problem is the SDK producing a double‑encoded
join_request
. Summary and immediate guidance • The SDK builds
join_request
by wrapping the JWT you give it. If the SDK receives a token that’s already encoded/wrapped, it will encode again and produce the "cannot unmarshal wrapped join request" error and trigger
rtc/v1/validate
in some flows. • The fix is to ensure the SDK receives the raw join JWT (no Base64/URL‑encoding, no JSON stringification, no URL‑wrapping) exactly as generated by your server. Quick checks to perform now • Confirm the value you pass into
connect(...)
(or
join(...)
) is the plain JWT string. Do not pass a token inside another object or as an encoded string. • Verify the delivery path: make sure no middleware, query param encoding, or client helper is altering the token (e.g.,
encodeURIComponent
, extra Base64, or JSON.stringify). • Test with a minimal reproduce: call
connect(url, "<raw-jwt>")
in the browser console using the JWT produced by your server. If that succeeds, the double‑encoding is happening in your app code/path. Next step I can take • Paste the small snippet where you call the SDK’s
connect
(redact the JWT). Also show how the JWT is delivered to the client (response body, query param, or injected script). I’ll point to the exact place an extra encode could be happening and the minimal change to stop it. Optional: SDK version note • You’re on v2.19.0 — if after we confirm your app isn’t modifying the token I can help verify whether this is a known SDK bug and suggest a version to upgrade to., with interactive elements
c
My app isn't modifying the token at all
t
Thanks — I’m responding to your confirmation that your app isn’t modifying the token and you still see the SDK double‑encoding the
join_request
. To diagnose quickly I need a minimal reproducible snapshot from your client environment (redact the JWT). Please provide all of the following: 1. The exact line(s) where you call the SDK to connect (e.g.,
connect(...)
or
Room.connect(...)
) — paste the snippet around that call. 2. How the JWT is delivered to the client (one of: response JSON, query param, injected into HTML, from localStorage, etc.). Show the code that reads that value immediately before the SDK call. 3. A redacted example of the JWT as seen in the browser right before you pass it to the SDK (replace the middle with … but keep the structure, e.g.,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIx...abc
). 4. Confirm any intermediaries between server and client (CDN, proxy, service worker, rewrite rules, or a framework SSR step). If you prefer to test first: open the browser console and call the SDK directly with the raw JWT you got from the server, e.g.: 1. Copy the JWT string from your network response. 2. Run the minimal connect call in console with that JWT (redact in shared logs if you paste it here). If that succeeds, the double‑encoding is happening before the SDK call in your app code/path. Share the requested snippets and console test result and I’ll point to the exact place causing the extra encoding or confirm if this looks like an SDK bug. , with interactive elements