windmill-labs/windmill · error

Draft app "${path}" has no policy to deploy.

Error message

Draft app "${path}" has no policy to deploy.

What it means

Thrown while deploying a raw app draft in the chat's deployDraft tool. Before deploying, the tool recomputes the app's policy (recomputeAppPolicy) from its runnables and data; if the resulting appValue.policy is falsy, there is no permission policy to ship, and deploying would leave the app without access rules. The tool aborts and asks for a draft with a computed policy.

Source

Thrown at frontend/src/lib/components/copilot/chat/global/core.ts:7415

						: undefined
					assertDraftBasedOnLatest(
						'app',
						path,
						draft.parentVersionId,
						deployedApp?.versions?.[deployedApp.versions.length - 1],
						force
					)
				}
				const appValue: AppDraftValue = {
					...appDraft,
					files: { ...(appDraft.files ?? {}) },
					runnables: { ...(appDraft.runnables ?? {}) },
					data: appDraft.data ?? { ...DEFAULT_RAW_APP_DATA }
				}
				await recomputeAppPolicy(appValue)
				const policy = appValue.policy
				if (!policy) {
					throw new Error(`Draft app "${path}" has no policy to deploy.`)
				}

				// An app deployed on its own while a path runnable still points at a draft
				// is deployed and broken — the deploy has to say so, not just report success.
				const undeployedTargets = await undeployedRunnableTargets(workspace, appValue.runnables)
				if (undeployedTargets.length > 0) {
					deployNote =
						`These backend runnables point at items that are NOT deployed, so they fail at runtime: ` +
						`${undeployedTargets.join(', ')}. Deploy those items too, and tell the user the app is ` +
						`not working until they are.`
				}

				toolCallbacks.setToolStatus(toolId, {
					content: `Bundling app "${path}"...`
				})
				const bundle = await bundleRawAppDraft({
					workspace,
					files: appValue.files,

View on GitHub (pinned to e474e8803c)

Solutions

  1. Open the raw app draft and ensure its runnables/data are well-formed so a policy can be computed, then redeploy.
  2. Check the draft against DEFAULT_RAW_APP_DATA to spot missing fields the policy derivation relies on.
  3. If recomputation is failing on valid data, investigate recomputeAppPolicy / rawAppPolicy for a regression.

Example fix

// before: draft.data missing expected sections
await deployDraft({ type: 'raw_app', path: 'a/admin_panel' })
// Error: Draft raw_app "a/admin_panel" has no policy to deploy.

// after: restore the draft's data/runnables so recomputeAppPolicy derives a policy
appDraft.data = { ...DEFAULT_RAW_APP_DATA, ...edits }
await deployDraft({ type: 'raw_app', path: 'a/admin_panel' })
Defensive patterns

Strategy: validation

Validate before calling

import { DEFAULT_RAW_APP_DATA } from '$lib/components/raw_apps/rawAppData'
const appDraft = (await getGlobalDraft(ws, 'raw_app', path))?.value
if (appDraft && (!appDraft.runnables || !appDraft.data)) {
  appDraft.data = { ...DEFAULT_RAW_APP_DATA, ...(appDraft.data ?? {}) }
}
await deployDraft({ type: 'raw_app', path, workspace: ws })

Type guard

function rawAppDraftHasPolicyInputs(draft) {
  return draft != null && draft.value != null &&
    typeof draft.value === 'object' && 'runnables' in draft.value && 'data' in draft.value
}

Try / catch

try {
  await deployDraft({ type: 'raw_app', path, workspace })
} catch (e) {
  if (/has no policy to deploy/.test(e.message)) {
    // repair the draft's runnables/data in the editor, then retry
  } else throw e
}

Prevention

When it happens

Trigger: Deploying a raw_app whose draft, after policy recomputation, yields appValue.policy == null — e.g. malformed/absent policy-producing fields in the draft (runnables/data shape the policy computer cannot derive a policy from).

Common situations: A raw app draft created by the AI with a runnables/data shape missing what rawAppPolicy expects; hand-edited draft state that dropped the policy section; a DEFAULT_RAW_APP_DATA regression after schema changes.

Related errors


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