windmill-labs/windmill · error · Error

${drawerConfigs[request.key].label} drawer is not ready

Error message

${drawerConfigs[request.key].label} drawer is not ready

What it means

getEditor in CreatedResourceActionDrawers.svelte waits one tick plus one animation frame for the drawer's editor component to mount, then throws if it is still undefined. The thrown message names the drawer label from drawerConfigs, indicating the drawer UI was asked to open but its editor instance never became available.

Source

Thrown at frontend/src/lib/components/copilot/chat/CreatedResourceActionDrawers.svelte:116

		return current ? `Edit ${drawerConfigs[current.key].label} ${current.path}` : 'Edit trigger'
	})

	async function getEditor(request: ActiveDrawerState): Promise<EditorHandle | undefined> {
		await request.promise
		await tick()
		await nextAnimationFrame()

		if (activeDrawer?.id !== request.id) {
			return undefined
		}

		if (!editor) {
			await tick()
			await nextAnimationFrame()
		}

		if (!editor) {
			throw new Error(`${drawerConfigs[request.key].label} drawer is not ready`)
		}
		return editor
	}

	async function openCreatedResource(action: ToolDisplayAction) {
		if (action.type !== 'open_created_resource') {
			return
		}

		if (action.resource === 'resource') {
			await resourceEditorDrawer?.initEdit(action.path)
			return
		}

		if (action.resource === 'variable') {
			await variableEditor?.editVariable(action.path)
			return
		}

View on GitHub (pinned to e474e8803c)

Solutions

  1. Verify request.key exists in drawerConfigs and maps to a drawer that renders an editor
  2. Increase/verify the wait: ensure the drawer markup is actually rendered (not behind an {#if} that is still false) before calling getEditor
  3. Wrap the getEditor call in try/catch and surface a retry or close the drawer instead of an unhandled rejection

Example fix

// before
const editor = await getEditor(request)
// after
let editor
try {
  editor = await getEditor(request)
} catch {
  sendUserToast('Could not open the editor drawer, please retry', true)
  return
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!drawerConfigs[request.key]) { sendUserToast('Unknown drawer', true); return }

Type guard

function hasDrawer(key: string): key is keyof typeof drawerConfigs { return key in drawerConfigs }

Try / catch

try { const editor = await getEditor(request) } catch { sendUserToast('Editor failed to open, please retry', true); activeDrawer = undefined }

Prevention

When it happens

Trigger: openCreatedResource / openDrawer sets a request; getEditor is called and after `await tick()` + `await nextAnimationFrame()` the `editor` variable is still falsy — e.g. the drawer component failed to mount, the request.key has no matching drawerConfig entry rendering an editor, or the drawer was closed synchronously before mounting.

Common situations: Race between the AI chat applying a tool action and the drawer's conditional rendering; a key not present in drawerConfigs so no editor is ever created; component torn down mid-await so the editor binding never populates.

Related errors


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