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.

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)

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.