LLMs.txt: Complete documentation index for AI agents
Handling embed errors

Handling embed errors

Important

In Visual Embed SDK v1.53.0 and later, EmbedEvent.Error includes a severity field that categorizes errors into three severity levels: SEV1, SEV2, and SEV3. If your app handles all errors the same way, you may want to update your integrations to distinguish between critical errors (SEV1) and less severe errors (SEV2, SEV3).

For more information, see Error severity levels.

The ThoughtSpot Visual Embed SDK provides a layered approach to error handling. EmbedEvent.Error is a real-time outbound event that the embedded ThoughtSpot iframe emits to the host app. It signals that something went wrong inside the SDK, inside the embedded app (the iframe), or because the host sent an invalid HostEvent payload.

Unlike most embed events, which the SDK caches and replays to late subscribers, EmbedEvent.Error is not cached or replayed. Every emission is independent, so you must register a handler before an error occurs.

EmbedEvent.Error fires per embed component. Register the handler before you call render().

Trigger sources🔗

Embed errors surface through distinct channels for the following failure categories:

SDK or configuration validation🔗

When SDK or configuration errors occur, the internal handleError(errorDetails) method in the embed component:

  1. Sets isError = true, which permanently blocks future renderIFrame calls on this instance.

  2. Calls executeCallbacks(EmbedEvent.Error, { severity: SEV3, …​errorDetails }). The default severity is SEV3 unless the error sets its own.

  3. Logs via logger.error(errorDetails).

Conditioncodeseveritymessage emitted

init() was not called before render()

INIT_ERROR

SEV1

"You need to init the ThoughtSpot SDK module first"

liveboardId is missing in LiveboardEmbed

LIVEBOARD_ID_MISSING

SEV1

"Please select a Liveboard to embed."

Both hiddenActions and visibleActions passed

CONFLICTING_ACTIONS_CONFIG

SEV3

"You cannot have both hidden actions and visible actions"

Both hiddenTabs and visibleTabs passed

CONFLICTING_TABS_CONFIG

SEV3

"You cannot have both hidden Tabs and visible Tabs"

trigger() called before render()

RENDER_NOT_CALLED

SEV3

"Please call render before triggering events"

trigger() called with undefined event type

HOST_EVENT_TYPE_UNDEFINED

SEV3

"Host event type is undefined"

Auth failure during renderIFrame

LOGIN_FAILED

SEV1

The message of the caught auth or login error, or "Login failed". The error field contains the caught error object.

The SDK emits these errors with the following payload:

{
  "errorType": "VALIDATION_ERROR",
  "message": "You cannot have both hidden actions and visible actions",
  "code": "CONFLICTING_ACTIONS_CONFIG",
  "severity": 3,
  "error": "You cannot have both hidden actions and visible actions"
}

The error field is retained for backward compatibility. For more information about the payload fields, see EmbedErrorDetailsEvent.

HostEvent validation🔗

When the host sends a HostEvent with an invalid payload or a context mismatch, the event bridge validates it against the HostEvent schema. On failure, the SDK emits EmbedEvent.Error with code embedErrorCodes.HOST_EVENT_VALIDATION. The trigger() call also rejects with the validation error.

{
  "type": "Error",
  "data": {
    "errorType": "VALIDATION_ERROR",
    "message": "<human-readable description of what field failed>",
    "code": "HOST_EVENT_VALIDATION",
    "error": "<human-readable description of what field failed>"
  },
  "status": "end",
  "severity": 3
}
Important

If useHostEventsV2 is not enabled, or shouldBypassPayloadValidation is true, the SDK logs validation failures as console warnings. They never reach your EmbedEvent.Error handler.

Runtime filter or cross-filter errors🔗

Filter operations can fail inside the iframe with typed errors:

eventErrorTypeTypical message pattern

SingleValueFilter

"Filter {name}: Cannot pass multiple filtering elements to this single value filter."

NonExistFilter

"UpdateFilters could not update the filter on {name} as it is not an existing filter…​"

InvalidDateValue

"UpdateFilters could not update the filter on {name} as invalid date value provided."

InvalidOperator

"UpdateFilters could not update the filter on {name} as invalid operator value provided."

WrongVizId

"UpdateCrossFilters could not update the filter as invalid VizId value provided."

NotAWorksheet

"UpdateCrossFilters could not update the filter as VizId does not consist any worksheet."

NoFilterableColumnPresent

"Could not apply CrossFilter…​"

filterExistsOrNoAttributeColumn

"UpdateCrossFilters could not update the filter as column is not an attribute…​"

InvalidColumnId

"Invalid ColumnId provided"

Fullscreen

"Failed to enable fullscreen, This may be happening because there was no user interaction…​"

NoActivePersonalisedViewsError

"No Personalized Liveboard view is selected."

PersonalisedViewNotFound

"No Personalised View found matching the provided viewId or viewName."

Network events🔗

A global listener for the browser offline event on window emits EmbedEvent.Error with a different payload shape:

{
  "errorType": "NETWORK",
  "message": "Network not Detected. Embed is offline. Please reconnect and refresh",
  "code": "NETWORK_ERROR",
  "severity": 2,
  "offlineWarning": "Network not Detected. Embed is offline. Please reconnect and refresh"
}

Error types🔗

EmbedEvent.Error fires when the following types of errors occur:

Error typeDescription

API

API call failure. This error occurs when an API request is blocked.

Example:

searchEmbed.on(EmbedEvent.Error, (error) => {
    console.log(error);
    // { type: "Error", data: { errorType: "API", error: { message: '...', error: '...' } } }
});

FULLSCREEN

Error in presenting a Liveboard or visualization in full-screen mode.

liveboardEmbed.on(EmbedEvent.Error, (error) => {
    console.log(error);
    // { type: "Error", data: { errorType: "FULLSCREEN", error: {
    //   message: "Fullscreen mode is not available",
    // } }}
});

SINGLE_VALUE_FILTER

Error in updating filter values. This error occurs when a single-value filter is applied to a Liveboard and the user tries to update this filter with multiple values.

liveboardEmbed.on(EmbedEvent.Error, (error) => {
    console.log(error);
    // { type: "Error", data: { errorType: "SINGLE_VALUE_FILTER", error: {
    //   message: "Filter {filter_name}: Cannot pass multiple filtering elements to this single value filter.",
    // } }}
});

NON_EXIST_FILTER

Error in applying filter due to a non-existent filter.

liveboardEmbed.on(EmbedEvent.Error, (error) => {
    console.log(error);
    // { type: "Error", data: { errorType: "NON_EXIST_FILTER", error: {
    //   message: "UpdateFilters could not update the filter on {filter_name} as it is not an existing filter in the Liveboard. Please edit the Liveboard and add {filter_name} as a filter chip in order to update it programmatically.",
    // } }}
});

INVALID_DATE_VALUE

Error due to an invalid date value in a filter. For example, if the column name is Commit Date and a correct date value is not specified, the INVALID_DATE_VALUE error event is fired.

liveboardEmbed.on(EmbedEvent.Error, (error) => {
    console.log(error);
    // { type: "Error", data: { errorType: "INVALID_DATE_VALUE", error: {
    //   message: "UpdateFilters could not update the filter on {filter_name} as invalid date value provided.",
    // } }}
});

INVALID_OPERATOR

Error due to an invalid operator in filter properties. For example, if you try to apply filters on the Revenue column with the operator as LT and specify multiple values, it may result in an error.

liveboardEmbed.on(EmbedEvent.Error, (error) => {
    console.log(error);
    // { type: "Error", data: { errorType: "INVALID_OPERATOR", error: {
    //   message: "UpdateFilters could not update the filter on {filter_name} as invalid operator value provided.",
    // } }}
});

Error severity levels🔗

The EmbedEvent.Error payload includes a severity field that categorizes errors into three levels:

SeverityDescriptionRecommended handling

SEV1

The embed is down: nothing usable is on screen, for example, because of an SDK initialization failure, a login failure, or an app crash.

Consider tearing down the embed and re-initializing, or showing a custom error message to the user.

SEV2

An error was shown to the user; the embed still works.

Log the error for monitoring. No immediate action is required unless the error indicates a persistent issue.

SEV3

Everything else, including validation of the embedder’s own input.

Log the error for debugging. These errors are typically not user-facing and can often be ignored if the application is functioning correctly.

The severity field is an optional numeric value that maps to the EmbedErrorSeverity enum: SEV1 is 1, SEV2 is 2, and SEV3 is 3. If an error does not set a severity, the SDK defaults to SEV3.

{
  "type": "Error",
  "data": {
    "errorType": "API",
    "error": {
      "message": "..."
    },
    "severity": 2
  }
}
Note

The severity field is backward compatible. If your application does not use the severity field, the error handling behavior remains unchanged.

Payload shapes🔗

EmbedEvent.Error emits one of the following payload shapes:

// SDK / auth error
{
  errorType: string;
  message: string | string[];
  code: string;
  severity?: number;
  error?: unknown; // retained for backward compatibility
}

// HostEvent validation error
{
  type: 'Error';
  data: { errorType: string; message: string; code: 'HOST_EVENT_VALIDATION'; error: string };
  status: string;
  severity?: number;
}

// Filter / runtime error (from embedded app)
// — matches one of the eventErrorType patterns above

// Network offline
{
  errorType: 'NETWORK';
  message: string;
  code: 'NETWORK_ERROR';
  severity: number;
  offlineWarning: string;
}

How to subscribe🔗

The following example shows how to handle each EmbedEvent.Error payload shape.

import { LiveboardEmbed, EmbedEvent } from '@thoughtspot/visual-embed-sdk';

const embed = new LiveboardEmbed('#container', {
  liveboardId: 'your-liveboard-id',
});

// Register BEFORE render() — errors can fire during initialization
embed.on(EmbedEvent.Error, (payload) => {

  // SDK/auth error
  if (payload?.error) {
    console.error('[SDK Error]', payload.code, payload.error);
    return;
  }

  // HostEvent validation error (your payload is malformed)
  if (payload?.data?.code === 'HOST_EVENT_VALIDATION') {
    console.error('[HostEvent validation failed]', payload.data.message);
    return;
  }

  // network offline
  if (payload?.offlineWarning) {
    showOfflineBanner(payload.offlineWarning);
    return;
  }

  // runtime filter/action error from the iframe
  console.warn('[Embed runtime error]', payload);
});

embed.render();

Handling HostEvent errors🔗

The following example shows how to handle errors from a trigger() call.

import { HostEvent } from '@thoughtspot/visual-embed-sdk';

async function updateRegionFilter() {
  try {
    const result = await embed.trigger(HostEvent.UpdateRuntimeFilters, [
      { columnName: 'Region', operator: 'EQ', values: ['West'] },
    ]);

    // Timeout is a resolve, not a reject — check explicitly
    if (result instanceof Error) {
      console.error('HostEvent timed out:', result.message);
      return;
    }

    console.log('HostEvent succeeded:', result);
  } catch (err) {
    // Rejection = iframe returned an explicit error in the response
    console.error('HostEvent rejected by iframe:', err);
  }
}

Error handling guidelines🔗

Error categoryDetection and recovery

SDK init config error

Detection mechanism: EmbedEvent.Error

Payload/data: { errorType, message, code, severity, error }

Recovery action: Fix the configuration. Destroy the embed, then create and render a new instance.

Auth failure (SDK layer)

Detection mechanism: AuthStatus.FAILURE on init emitter

Payload/data: AuthFailureType

Recovery action: Check getAuthToken and credentials. Use suppressErrorAlerts for custom UI.

Auth failure (iframe layer)

Detection mechanism: EmbedEvent.AuthFailure

Recovery action: Show a login prompt. Destroy the embed, then create and render a new instance.

Session expired

Detection mechanism: EmbedEvent.AuthExpire

Recovery action: Refresh token. Use autoLogin: true for a transparent refresh.

Idle session timeout

Detection mechanism: EmbedEvent.IdleSessionTimeout and AuthStatus.FAILURE(IDLE_SESSION_TIMEOUT)

Recovery action: Use autoLogin: true. Prompt re-authentication.

Third-party cookies blocked

Detection mechanism: EmbedEvent.NoCookieAccess and AuthStatus.FAILURE(NO_COOKIE_ACCESS)

Recovery action: Switch to TrustedAuthTokenCookieless. Use ignoreNoCookieAccess: true to suppress alert.

User logout

Detection mechanism: EmbedEvent.AuthLogout and AuthStatus.LOGOUT

Recovery action: Redirect to login or clear state.

Duplicate token

Detection mechanism: AuthStatus.FAILURE(SDK) and alert() (suppressible)

Payload/data: DUPLICATE_TOKEN_ERR string

Recovery action: Always return a fresh token from getAuthToken.

Invalid token

Detection mechanism: AuthStatus.FAILURE(SDK) and logger.error

Payload/data: INVALID_TOKEN_ERROR string

Recovery action: Verify token generation on the server.

Network offline

Detection mechanism: EmbedEvent.Error

Payload/data: { errorType: "NETWORK", code: "NETWORK_ERROR", offlineWarning: string }

Recovery action: Show offline UI. Reconnect and reload.

HostEvent validation error

Detection mechanism: EmbedEvent.Error

Payload/data: { type, data: { code: "HOST_EVENT_VALIDATION", message } }

Recovery action: Fix the HostEvent payload. Enable useHostEventsV2: true in development.

HostEvent timeout (30 seconds)

Detection mechanism: trigger() resolves with Error

Payload/data: Error("Trigger timed-out…​")

Recovery action: Check if the iframe is still mounted. Call reload() if needed.

HostEvent iframe rejection

Detection mechanism: trigger() rejects

Payload/data: Error from iframe

Recovery action: Inspect the rejection payload. See the HostEvent validation error row.

Filter errors at runtime

Detection mechanism: EmbedEvent.Error

Payload/data: eventErrorType message string

Recovery action: Fix filter parameters. Validate against current Liveboard/answer filters.

Destroying an embed instance🔗

To remove an embedded ThoughtSpot component, for example, during route changes, error recovery, or cleanup in single-page apps, call embed.destroy(). This is the only supported way to tear down an embed instance.

Calling embed.destroy() performs the following cleanup steps in order:

  1. Removes fullscreen change handlers.

  2. Disconnects the resize observer.

  3. Unsubscribes window-level event listeners registered by the embed.

  4. Removes any pre-render wrappers created during initialization.

  5. Sends an internal notification to the embedded iframe so that it can release its own resources.

  6. Removes the iframe DOM node from the page.

If the embed has not rendered yet, destroy() skips steps 5 and 6.

After destroy() completes, the embed instance is no longer usable. To re-embed, create a new instance and call render() again.

After an SDK or configuration error, the embed instance blocks all further render() calls. To recover, destroy the instance, fix the cause, and create a new one.

Example: Destroy and re-create🔗

import {
  LiveboardEmbed,
  HostEvent,
  EmbedEvent,
} from '@thoughtspot/visual-embed-sdk';

// Create and render the embed
const embed = new LiveboardEmbed(document.getElementById('embed-container'), {
  liveboardId: 'd084c256-e284-4fc4-b80c-111111111111',
});
embed.render();

// Later, tear it down
embed.destroy();

// To re-embed, create a new instance
const newEmbed = new LiveboardEmbed(document.getElementById('embed-container'), {
  liveboardId: 'd084c256-e284-4fc4-b80c-111111111111',
});
newEmbed.render();

Wait for iframe cleanup🔗

By default, destroy() sends the internal teardown notification to the iframe and removes the DOM node immediately, without waiting for the iframe to finish its own cleanup.

If your application requires the iframe to complete its cleanup before the DOM node is removed, set waitForCleanupOnDestroy to true in the init() configuration:

import { init, AuthType } from '@thoughtspot/visual-embed-sdk';

init({
  thoughtSpotHost: 'https://<your-ts-instance>.thoughtspot.cloud',
  authType: AuthType.TrustedAuthTokenCookieless,
  // ...other init options
  waitForCleanupOnDestroy: true,
  cleanupTimeout: 5000, // milliseconds; optional
});
ParameterDefaultDescription

waitForCleanupOnDestroy

false

When true, destroy() waits for the embedded app to acknowledge the teardown notification before removing the iframe from the DOM.

cleanupTimeout

5000

The maximum time, in milliseconds, that destroy() waits for the embedded app’s cleanup response when waitForCleanupOnDestroy is true. If the timeout is reached, the iframe is removed regardless.

Warning

Do not call embed.trigger(HostEvent.DestroyEmbed) directly. The SDK triggers this event for you when you call embed.destroy(). Triggering it directly throws a TypeError and does not tear down the embed or remove the iframe.

Best practices🔗

  • Always register an event listener for EmbedEvent.Error on your embed instance to capture and handle errors emitted by the embedded ThoughtSpot application. Register EmbedEvent.Error before calling render().

  • Inspect and categorize error payloads. The error event provides a payload with fields such as errorType, message, and code. Do not assume that payload.error always exists. Offline errors use offlineWarning, and validation errors use code.

  • Do not destroy the embed for every error. Inspect the error first to determine whether you need to display a host fallback page. Not all errors are fatal, and ThoughtSpot handles some failures internally. Destroy the embed only when the error leaves it unusable. For more information, see Destroying an embed instance.

  • Call embed.destroy() when you remove the embed container, navigate away from the page, or unmount the component. Do not reuse a destroyed instance. Create a new one instead.

  • Provide contextual and user-friendly error messages based on the errorType and error details. Avoid exposing raw error objects or stack traces to your application users.

  • Enable useHostEventsV2: true in development/staging to surface HostEvent payload errors early.

  • Log errors for diagnostics.

  • Simulate error scenarios during development, such as network failures and invalid filters, to verify that your error handling logic works as expected.

  • Do not set shouldBypassPayloadValidation: true in production environments. Validation errors become invisible console warnings.

  • Do not call trigger() before render(). The SDK emits an EmbedEvent.Error with the RENDER_NOT_CALLED code and returns null.

Try it out in the Visual Embed Playground🔗

Try out the embed events in the Visual Embed Playground and preview changes.

Try Embed events in Playground

Additional resources🔗

© 2026 ThoughtSpot Inc. All Rights Reserved.