cube-js/cube · error
Live-preview token is invalid
Error message
Live-preview token is invalid
What it means
LivePreviewWatcher.setAuth decodes the middle segment of a JWT-style token (base64 JSON) to extract deploymentId and url. If JSON.parse or Buffer decoding fails — meaning the token is malformed, truncated, or not a JWT — it logs the internal exception and throws 'Live-preview token is invalid'.
Source
Thrown at packages/cubejs-backend-cloud/src/live-preview.ts:39
private lastHash: string | undefined;
private log(message: string) {
console.log('☁️ Live-preview:', message);
}
public setAuth(token: string): AuthObject {
try {
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
this.auth = {
auth: token,
deploymentId: payload.deploymentId,
url: payload.url,
};
return this.auth;
} catch (e: any) {
internalExceptions(e);
throw new Error('Live-preview token is invalid');
}
}
public startWatch(): void {
if (!this.auth) {
throw new Error('Auth isn\'t set');
}
if (!this.watcher) {
this.log('Start with Cube Cloud');
this.watcher = chokidar.watch(
process.cwd(),
{
ignoreInitial: false,
ignored: [
'**/node_modules/**',
'**/.*'
]View on GitHub (pinned to 7d981676b3)
Solutions
- Copy the full live-preview JWT from the Cube Cloud UI on one line, without quotes or trailing whitespace.
- Verify the token has the JWT form header.payload.signature and base64-decode the payload to confirm deploymentId/url are present.
- Set the token via the proper env var/config rather than manual paste to avoid truncation.
- Obtain a fresh live-preview token from Cube Cloud if the old one was revoked.
Example fix
// before
watcher.setAuth(process.env.CUBE_CLOUD_TOKEN ?? ''); // empty -> invalid
// after
const token = process.env.CUBE_LIVE_PREVIEW_TOKEN;
if (!token || token.split('.').length !== 3) throw new Error('CUBE_LIVE_PREVIEW_TOKEN must be a JWT');
watcher.setAuth(token); Defensive patterns
Strategy: validation
Validate before calling
function looksLikeJwt(token: string | undefined): boolean {
if (!token || token.split('.').length !== 3) return false;
try {
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
return !!payload.deploymentId && !!payload.url;
} catch { return false; }
}
// usage: if (!looksLikeJwt(process.env.CUBE_LIVE_PREVIEW_TOKEN)) throw ... Type guard
function isValidLivePreviewToken(t: unknown): t is string {
return typeof t === 'string' && t.split('.').length === 3 && (() => { try { JSON.parse(Buffer.from(t.split('.')[1], 'base64').toString()); return true; } catch { return false; } })();
} Try / catch
try {
watcher.setAuth(token);
} catch (e) {
if (e instanceof Error && e.message === 'Live-preview token is invalid') {
// prompt user / fail startup with guidance on copying the full JWT
} else throw e;
} Prevention
- Paste the token as a single unquoted line; prefer env vars over manual input.
- Validate the JWT shape (three dot-separated base64 segments) before calling setAuth.
- Use the live-preview token type specifically — not a deploy or API token.
When it happens
Trigger: Calling setAuth with a value that has no dot-separated base64 JSON payload: an empty string, an API key instead of a JWT, a truncated token, or a token copied with whitespace/quotes.
Common situations: Copy-pasting the wrong credential type (e.g. a deploy auth token instead of a live-preview JWT) into the live-preview token prompt; terminal wrapping breaking the token across lines; missing env var yielding an empty string.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- JWT token is not present in the response
- Auth isn't set
- No app secret found
- Unable to decode JWT key
- JWT without kid inside headers
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/7e98ed3a3efe950a.
Report an issue: GitHub.