{"record":{"id":"831005a2583e319d","repo":"windmill-labs/windmill","slug":"userdraft-no-workspace-available-pass-opts-works","errorCode":null,"errorMessage":"UserDraft: no workspace available (pass opts.workspace or set $workspaceStore)","messagePattern":"UserDraft: no workspace available \\(pass opts\\.workspace or set \\$workspaceStore\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/userDraft.svelte.ts","lineNumber":166,"sourceCode":"\nfunction rememberWrite(\n\tworkspace: string,\n\titemKind: UserDraftItemKind,\n\tpath: string,\n\tval: unknown\n): void {\n\tconst mk = mapKey(workspace, itemKind, path)\n\tif (val === undefined) {\n\t\twrittenCache.delete(mk)\n\t} else {\n\t\twrittenCache.set(mk, { workspace, itemKind, path, val: snapshotDraftValue(val) })\n\t}\n}\n\nfunction resolveWorkspace(opts?: UserDraftOptions): string {\n\tconst ws = opts?.workspace ?? get(workspaceStore)\n\tif (!ws) {\n\t\tthrow new Error(\n\t\t\t'UserDraft: no workspace available (pass opts.workspace or set $workspaceStore)'\n\t\t)\n\t}\n\treturn ws\n}\n\nfunction mapKey(workspace: string, itemKind: UserDraftItemKind, path: string): string {\n\treturn `${workspace}/${itemKind}/${path}`\n}\n\nfunction liveEditorDraftKey(workspace: string, itemKind: UserDraftItemKind): string {\n\treturn `${workspace}/${itemKind}`\n}\n\nfunction snapshotDraftValue<V>(value: V | undefined): V | undefined {\n\tif (value === undefined) return undefined\n\ttry {\n\t\treturn structuredClone($state.snapshot(value)) as V","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/userDraft.svelte.ts#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nUserDraft.set('script', path, draft) // throws if store not ready\n// after\nconst ws = get(workspaceStore)\nif (ws) {\n  UserDraft.set('script', path, draft, { workspace: ws })\n}","handlingStrategy":"validation","validationCode":"import { get } from 'svelte/store'\nimport { workspaceStore } from '$lib/stores'\n\nfunction ensureWorkspace(opts?: { workspace?: string }): string {\n  const ws = opts?.workspace ?? get(workspaceStore)\n  if (!ws) throw new Error('UserDraft called before workspace was set')\n  return ws\n}\n// call ensureWorkspace() before any UserDraft API","typeGuard":"function hasWorkspace(opts?: { workspace?: string }): opts is { workspace: string } {\n  return typeof opts?.workspace === 'string' && opts.workspace.length > 0\n}","tryCatchPattern":"try {\n  UserDraft.set(itemKind, path, value)\n} catch (err) {\n  if (err instanceof Error && err.message.includes('no workspace available')) {\n    return // app not initialized or logged out; skip draft persistence\n  }\n  throw err\n}","preventionTips":["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"],"tags":["workspace","state","initialization","svelte"],"backgroundTag":"missing-context-state","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}