windmill-labs/windmill · error · Error
UserDraft: no workspace available (pass opts.workspace or se
Error message
UserDraft: no workspace available (pass opts.workspace or set $workspaceStore)
What it means
UserDraft's resolveWorkspace determines which workspace a draft belongs to. It takes opts.workspace, falling back to the $workspaceStore; if both are empty it throws because draft storage keys are workspace-scoped and cannot be computed.
Source
Thrown at frontend/src/lib/userDraft.svelte.ts:166
function rememberWrite(
workspace: string,
itemKind: UserDraftItemKind,
path: string,
val: unknown
): void {
const mk = mapKey(workspace, itemKind, path)
if (val === undefined) {
writtenCache.delete(mk)
} else {
writtenCache.set(mk, { workspace, itemKind, path, val: snapshotDraftValue(val) })
}
}
function resolveWorkspace(opts?: UserDraftOptions): string {
const ws = opts?.workspace ?? get(workspaceStore)
if (!ws) {
throw new Error(
'UserDraft: no workspace available (pass opts.workspace or set $workspaceStore)'
)
}
return ws
}
function mapKey(workspace: string, itemKind: UserDraftItemKind, path: string): string {
return `${workspace}/${itemKind}/${path}`
}
function liveEditorDraftKey(workspace: string, itemKind: UserDraftItemKind): string {
return `${workspace}/${itemKind}`
}
function snapshotDraftValue<V>(value: V | undefined): V | undefined {
if (value === undefined) return undefined
try {
return structuredClone($state.snapshot(value)) as VView on GitHub (pinned to e474e8803c)
Solutions
- Pass the workspace explicitly: UserDraft.set(itemKind, path, value, { workspace: ws })
- Ensure the call happens after app initialization so $workspaceStore is populated
- Guard the call site: skip draft operations when the workspace is falsy
- In tests, seed the workspace store (or pass opts.workspace) before invoking UserDraft
Example fix
// before
UserDraft.set('script', path, draft) // throws if store not ready
// after
const ws = get(workspaceStore)
if (ws) {
UserDraft.set('script', path, draft, { workspace: ws })
} Defensive patterns
Strategy: validation
Validate before calling
import { get } from 'svelte/store'
import { workspaceStore } from '$lib/stores'
function ensureWorkspace(opts?: { workspace?: string }): string {
const ws = opts?.workspace ?? get(workspaceStore)
if (!ws) throw new Error('UserDraft called before workspace was set')
return ws
}
// call ensureWorkspace() before any UserDraft API Type guard
function hasWorkspace(opts?: { workspace?: string }): opts is { workspace: string } {
return typeof opts?.workspace === 'string' && opts.workspace.length > 0
} Try / catch
try {
UserDraft.set(itemKind, path, value)
} catch (err) {
if (err instanceof Error && err.message.includes('no workspace available')) {
return // app not initialized or logged out; skip draft persistence
}
throw err
} Prevention
- Only call UserDraft APIs after app/workspace initialization
- Always pass { workspace } explicitly in non-component code and tests
- Guard draft writes during logout/workspace switches
- Seed workspaceStore in tests before exercising draft logic
When it happens
Trigger: Calling any UserDraft API (get/set/remove/ws helpers) before the workspace store is initialized, or outside a component/context where $workspaceStore is set, without passing { workspace } in opts.
Common situations: Module-level or early-lifecycle calls running before app init; usage in tests or stories without the workspace store mocked; workspace switched/cleared during logout while a draft operation is in flight; calling from a non-Svelte utility module where the store was never loaded.
Related errors
- Workspace not found
- No workspace selected
- ⚠️ No workspace bound. Sync commands will not work without
- Active instance ${activeName} not found in config
- No local file for ${scriptPath} to infer its S3Object parame
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/831005a2583e319d.
Report an issue: GitHub.