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
- 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)
- Deploy to Sanity hosted Studio (
autoUpdates: true or sanity deploy)
- Open the hosted Studio and navigate to a workspace that uses a non-default dataset (e.g.,
development with dataset development)
- Open the Presentation tool
- Open DevTools → Network tab, filter for
preview-url-secret
- 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., qa → production) 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.
Describe the bug
In a multi-workspace Studio with different datasets per workspace, the Presentation tool's
create-preview-secret.tsalways writessanity.previewUrlSecretdocuments to the first workspace's dataset (production), ignoring the active workspace's dataset configuration (development). This causesdefineEnableDraftMode(fromnext-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 devlocally — only the hosted Studio is affected.To Reproduce
autoUpdates: trueorsanity deploy)developmentwith datasetdevelopment)preview-url-secretcreate-preview-secret.ts:17sends mutation toproductiondataset instead ofdevelopmentWorkspace configuration:
CLI config:
Expected behavior
When in the
developmentworkspace, the Presentation tool should writesanity.previewUrlSecretdocuments to thedevelopmentdataset.Actual behavior
The Presentation tool writes
sanity.previewUrlSecretdocuments toproduction(the first workspace's dataset) regardless of which workspace is active.Network tab evidence (while in
developmentworkspace after full page reload):Local
sanity devwith the same config — correct dataset routing:Impact: The frontend's
defineEnableDraftModequeries thedevelopmentdataset for the preview secret, but the secret was written toproduction→ 401 Unauthorized → draft mode never enables →VisualEditingnever renders → Studio shows "Unable to connect to visual editing." Workspaces using the same dataset as the first workspace (e.g.,qa→production) work fine, masking the bug.Which versions of Sanity are you using?
Frontend:
next-sanity~10.1.4,@sanity/client^7.17.0,next15.5.13What operating system are you using?
macOS (Darwin 24.6.0)
Which versions of Node.js / npm are you running?
Additional context
Local
sanity devworks correctly. The samesanity.config.tswrites secrets to the correct dataset when running locally. The bug only manifests in the hosted Studio, where the URL rewrites from<studioHost>.sanity.studiotowww.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 increate-preview-secret.tsshould inherit the active workspace's dataset viauseSource().getClient(). In the hosted core-ui environment, this appears to resolve to the first/default workspace's dataset instead.