windmill-labs/windmill · error · Error

Draft diff not supported for kind ${kind}

Error message

Draft diff not supported for kind ${kind}

What it means

getDraftDiffValues in frontend/src/lib/utils_draft_deploy.ts (line 345) computes a deployed-vs-draft diff by looking up a getter in the OVERLAY_GETTERS map keyed by item kind, then canonicalizing both sides onto a shared field set. When the kind has no entry in OVERLAY_GETTERS (the map has no draft overlay representation for it), the code throws 'Draft diff not supported for kind ...'. Unlike the trigger dispatchers, this one intentionally guards against kinds whose draft shapes are too divergent to diff meaningfully.

Source

Thrown at frontend/src/lib/utils_draft_deploy.ts:345

		return {
			deployed: draftOnly ? EMPTY_DEPLOYED.app!(undefined) : deployed,
			draft: {
				summary: draftParts.summary ?? r.summary ?? '',
				value: draftParts.value,
				path: draftParts.draftPath ?? r.path
			},
			hasDraft: r.draft != null,
			noDeployed: r.no_deployed === true
		}
	} else {
		// Variables / resources / schedules / triggers: one overlay GET yields
		// both sides, but the draft side is the editor's state shape while the
		// deployed side is the backend row — they diverge enough to make a raw
		// diff pure noise. Canonicalize both onto a shared field set (same shaping
		// the compare page's `getItemValue` applies) so only real changes show.
		const getter = OVERLAY_GETTERS[kind]
		if (!getter) {
			throw new Error(`Draft diff not supported for kind ${kind}`)
		}
		const { deployed, draft, hasDraft, noDeployed } = splitOverlay(await getter(workspace, path))
		return {
			deployed: draftOnly ? {} : canonicalizeDraftDiffValue(kind, deployed, false),
			draft: canonicalizeDraftDiffValue(kind, draft, true),
			hasDraft,
			noDeployed
		}
	}
}

/**
 * Whether a draft's base is stale: the deployed version the draft forked from
 * no longer matches the current deployed head — a newer version was deployed
 * after the draft began, so deploying the draft would silently revert it.
 * Scripts compare the draft's `parent_hash` vs the deployed `hash`; flows the
 * pinned `version_id` vs the deployed head `version_id`; apps (incl. raw) the
 * pinned `parent_version` vs the head of `versions`. `r` is the item fetched

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check the `kind` in the error and confirm it should be diffable; if it is (e.g. a recently added kind), add an entry to OVERLAY_GETTERS returning { deployed, draft } for that kind.
  2. If the kind is not diffable by design, hide the diff action in the UI (guard with `kind in OVERLAY_GETTERS`) instead of invoking getDraftDiffValues.
  3. Update canonicalizeDraftDiffValue with a shaping branch for the new kind so the diff output is not raw noise.
  4. Ensure kind keys are in sync between the Kind union and OVERLAY_GETTERS after any rename.

Example fix

// before
const diff = await getDraftDiffValues('raw_app', workspace, path)
// after
if (kind in OVERLAY_GETTERS) {
  const diff = await getDraftDiffValues(kind, workspace, path)
} else {
  // hide the diff entry for this kind in the UI
}
Defensive patterns

Strategy: type-guard

Validate before calling

import { OVERLAY_GETTERS } from '$lib/utils_draft_deploy'
function canDiffDraft(kind: Kind): kind is keyof typeof OVERLAY_GETTERS {
  return kind in OVERLAY_GETTERS
}

Type guard

const OVERLAY_GETTERS = { script: getScriptOverlay, flow: getFlowOverlay /* ... */ } as const
type DiffableKind = keyof typeof OVERLAY_GETTERS
function isDiffableKind(k: Kind): k is DiffableKind {
  return k in OVERLAY_GETTERS
}

Try / catch

try {
  const diff = await getDraftDiffValues(kind, workspace, path)
} catch (e) {
  if (String(e?.message).startsWith('Draft diff not supported for kind')) {
    // fall back to the plain deploy view without a diff drawer
  } else throw e
}

Prevention

When it happens

Trigger: Calling getDraftDiffValues (via values, diffWorkspaceItem, or the {deployed,draft} overloads) with a kind that has no OVERLAY_GETTERS entry — e.g. raw_app, folder, resource_type, datatable_migration, or a new item kind added to the Kind union without a draft-diff getter.

Common situations: Trying to show a diff drawer for a newly supported deployable kind before adding its overlay getter; a kind renamed in the Kind union while the OVERLAY_GETTERS map still uses the old key; users hitting it on draft bundles like data_pipeline that are not diffable.

Related errors


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