Sanity Library Reference Docs
    Preparing search index...

    Interface StudioErrorHandlerBeta

    Call-site API for delegating unrecoverable request errors to the studio's built-in error UI (dialogs, verified forced logout).

    The studio never intercepts your requests — errors only reach this channel when you hand them over. Handle what you can locally (inline errors, toasts, fallbacks); delegate what you can't.

    Two shapes, both feeding the same dialog:

    const {attempt, handle} = useStudioErrorHandler()

    // 1. Thunk wrapper — the dialog's "Try again" re-invokes the thunk.
    // The thunk may return a promise or a (single-shot) observable:
    const user = await attempt(() => client.request({uri: '/users/me'}), {
    retryable: true,
    })

    // 2. Promise rejection handler — fire-and-surface, no retry:
    client.create(doc).catch(handle)

    Unclaimable errors (4xx other than 429, parse errors, ...) are re-thrown unchanged, so downstream .catch / catchError handlers still see them. 401s are claimed only when the API explicitly tags them as session expiry (SIO-401-AEX), in which case a forced logout follows; untagged resource-level 401s are re-thrown to the caller.

    interface StudioErrorHandler {
        attempt<T>(
            thunk: (attemptNumber: number) => PromiseLike<T> | Observable<T>,
            options?: RequestErrorReportOptions,
        ): Promise<T>;
        handle(err: unknown): Promise<never>;
    }
    Index

    Methods

    Methods

    • Beta

      Runs thunk and delegates claimable failures to the studio dialog. With retryable: true, the dialog's "Try again" re-invokes the thunk; the returned promise resolves with the first successful attempt. Unclaimable failures reject the returned promise.

      The thunk receives the attempt number (starting at 1), useful for logging or cache-busting. It may return a promise or an observable — an observable is drained to its last emitted value (single-shot request observables emit once and complete, so this is their value).

      The observable MUST be finite. attempt waits for completion, so a long-lived or multicast source (client.listen(), a Subject) would never resolve and would leak its subscription for the life of the returned promise. An observable that completes without emitting rejects with rxjs's EmptyError. Pass request-style observables only.

      Promises are eager, so the thunk must CREATE the request when called — retry works by invoking it again for a fresh request:

      // ✓ each invocation issues a new request
      attempt(() => client.fetch(query), {retryable: true})

      // ✗ the request already happened; retry re-awaits the same
      // settled rejection and the dialog just reappears
      const promise = client.fetch(query)
      attempt(() => promise, {retryable: true})

      Type Parameters

      • T

      Parameters

      Returns Promise<T>

    • Beta

      Promise rejection handler — use directly in .catch(handle). Claimable errors surface the studio dialog and leave the promise pending (the request is in limbo until the user reloads); unclaimable errors are re-thrown to the next .catch:

      client
      .create(doc)
      .catch(handle)
      .catch((err) => {
      // caller-domain errors (validation, permissions, 404, ...)
      })

      Parameters

      • err: unknown

      Returns Promise<never>