Skip to content

Presentation tool writes sanity.previewUrlSecret to wrong dataset in multi-workspace hosted Studio #3393

@manubuer

Description

@manubuer

Describe the bug

In a multi-workspace Studio with different datasets per workspace, the Presentation tool's create-preview-secret.ts always writes sanity.previewUrlSecret documents to the first workspace's dataset (production), ignoring the active workspace's dataset configuration (development). This causes defineEnableDraftMode (from next-sanity) on the frontend to return 401, because the frontend queries the correct dataset where the secret doesn't exist.

This works correctly with sanity dev locally — only the hosted Studio is affected.

To Reproduce

  1. Configure a multi-workspace Studio where at least one workspace uses a different dataset than the first workspace in the array (see workspace config below)
  2. Deploy to Sanity hosted Studio (autoUpdates: true or sanity deploy)
  3. Open the hosted Studio and navigate to a workspace that uses a non-default dataset (e.g., development with dataset development)
  4. Open the Presentation tool
  5. Open DevTools → Network tab, filter for preview-url-secret
  6. See: create-preview-secret.ts:17 sends mutation to production dataset instead of development

Workspace configuration:

// sanity.config.ts (simplified — two datasets, multiple workspaces)
export default defineConfig([
  // These workspaces use the "production" dataset
  { name: 'production',  dataset: 'production',  basePath: '/production',  plugins: [presentationTool({...})] },
  { name: 'qa',          dataset: 'production',  basePath: '/qa',          plugins: [presentationTool({...})] },
  // This workspace uses a different dataset: "development"
  { name: 'development', dataset: 'development', basePath: '/development', plugins: [presentationTool({...})] },
]);

CLI config:

// sanity.cli.ts
export default defineCliConfig({
  api: { projectId, dataset: 'development' },
  deployment: { autoUpdates: true }
});

Expected behavior

When in the development workspace, the Presentation tool should write sanity.previewUrlSecret documents to the development dataset.

Actual behavior

The Presentation tool writes sanity.previewUrlSecret documents to production (the first workspace's dataset) regardless of which workspace is active.

Network tab evidence (while in development workspace after full page reload):

production?tag=sanity.studio.sanity.preview-url-secret&returnIds=true&visibility=sync    200    create-preview-secret.ts:17
production?tag=sanity.studio&returnIds=true&returnDocuments=true&visibility=sync          200    create-preview-secret.ts:17

Local sanity dev with the same config — correct dataset routing:

# development workspace → mutates development dataset (correct)
development?tag=sanity.studio.sanity.preview-url-secret&returnIds=true&visibility=sync
development?tag=sanity.studio&returnIds=true&returnDocuments=true&visibility=sync

# production workspace → mutates production dataset (correct)
production?tag=sanity.studio.sanity.preview-url-secret&returnIds=true&visibility=sync
production?tag=sanity.studio&returnIds=true&returnDocuments=true&visibility=sync

Impact: The frontend's defineEnableDraftMode queries the development dataset for the preview secret, but the secret was written to production → 401 Unauthorized → draft mode never enables → VisualEditing never renders → Studio shows "Unable to connect to visual editing." Workspaces using the same dataset as the first workspace (e.g., qaproduction) work fine, masking the bug.

Which versions of Sanity are you using?

@sanity/cli (global)                   4.22.0
@sanity/document-internationalization   4.1.1
@sanity/eslint-config-studio            5.0.2
@sanity/icons                           3.7.4
@sanity/table                           1.1.4
@sanity/vision                         4.22.0
@sanity/visual-editing                  3.2.4
sanity                                 4.22.0

Frontend: next-sanity ~10.1.4, @sanity/client ^7.17.0, next 15.5.13

What operating system are you using?

macOS (Darwin 24.6.0)

Which versions of Node.js / npm are you running?

npm: 10.8.2
node: v20.19.4

Additional context

  • Local sanity dev works correctly. The same sanity.config.ts writes secrets to the correct dataset when running locally. The bug only manifests in the hosted Studio, where the URL rewrites from <studioHost>.sanity.studio to www.sanity.io/@<orgId>/studio/<appId>/... with _context={"mode":"core-ui"}. This suggests the core-ui platform layer interferes with the workspace's client/dataset resolution.

  • The useClient() call in create-preview-secret.ts should inherit the active workspace's dataset via useSource().getClient(). In the hosted core-ui environment, this appears to resolve to the first/default workspace's dataset instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions