windmill-labs/windmill · warning · Error

Missing context for draft fetch

Error message

Missing context for draft fetch

What it means

In frontend/src/lib/components/DraftBadge.svelte:149, fetchDraft() requires workspace, itemKind, and path to call DraftService.getDraftForUser; if any is missing it throws "Missing context for draft fetch". This guards against querying drafts for an item that is not (yet) identified.

Solutions

  1. Save the item first so it has a path before draft lookups
  2. Ensure the component is only rendered when workspace and path are set (use {#key path} or a guard)
  3. Check where itemKind/path are sourced and fix the empty value

Example fix

// before
{#if showDraft}<DraftBadge ... />{/if}
// after
{#if showDraft && path}<DraftBadge ... />{/if}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!workspace || !itemKind || !path) return; // skip draft fetch until item is identified

Type guard

function canFetchDraft(ctx: { workspace?: string; itemKind?: string; path?: string }): ctx is { workspace: string; itemKind: string; path: string } {
  return Boolean(ctx.workspace && ctx.itemKind && ctx.path);
}

Try / catch

try {
  draft = await fetchDraft(owner);
} catch {
  draft = undefined; // no draft yet or missing context — treat as no draft
}

Prevention

When it happens

Trigger: DraftBadge rendered for an unsaved/new item with no path, or outside a workspace context — e.g. the component mounts before the item's path is assigned.

Common situations: Creating a brand-new script/flow and opening the draft badge before first save; component rendered in a context without workspace selection; a race where path prop is briefly empty on mount.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/d8801e8e4567f905. Report an issue: GitHub.

Appendix: source

Thrown at frontend/src/lib/components/DraftBadge.svelte:149

	)

	let busyFor = $state<string | null>(null)
	let diffDrawer: DiffDrawer | undefined = $state(undefined)
	let migrateOpen = $state(false)
	// The hover popover sits above the diff drawer / migrate modal (z-index), so
	// close it before opening either or it would cover them.
	let popoverOpen = $state(false)

	// Legacy (no-owner) drafts can only be resolved by workspace admins / superadmins.
	const canMigrateLegacy = $derived(!!$userStore?.is_admin || !!$userStore?.is_super_admin)

	function ownerKey(owner: DraftUser): string {
		return owner.username ?? '__legacy__'
	}

	async function fetchDraft(owner: DraftUser): Promise<unknown> {
		if (!workspace || !itemKind || !path) {
			throw new Error('Missing context for draft fetch')
		}
		return (
			await DraftService.getDraftForUser({
				workspace,
				kind: itemKind,
				path,
				username: owner.username ?? undefined
			})
		).value
	}

	async function viewDiff(owner: DraftUser) {
		if (!workspace || !itemKind || !path) return
		busyFor = ownerKey(owner)
		try {
			const [draftValue, deployed] = await Promise.all([
				fetchDraft(owner),
				fetchDeployedValueForDiff(workspace, itemKind, path)

View on GitHub (pinned to e474e8803c)