windmill-labs/windmill · error

no target folder

Error message

no target folder

What it means

runBulk's 'move' action requires opts.target (the destination folder path). It throws synchronously per item when target is missing, since moving without a destination is a caller bug, not an item failure.

Source

Thrown at frontend/src/lib/components/home/bulkActions.ts:145

export type BulkOutcome = { item: BulkItem; error?: string }

/**
 * Apply `action` to each item in turn, never aborting the batch on a failure —
 * every item gets its own outcome so partial success is reported rather than
 * hidden. `onProgress` is called after each item with the number completed.
 */
export async function runBulk(
	action: BulkAction,
	items: BulkItem[],
	ctx: BulkContext,
	opts: { target?: string; onProgress?: (done: number) => void } = {}
): Promise<BulkOutcome[]> {
	const outcomes: BulkOutcome[] = []
	for (const item of items) {
		try {
			switch (action) {
				case 'move':
					if (!opts.target) throw new Error('no target folder')
					await moveItem(ctx, item, opts.target)
					break
				case 'archive':
					await setArchived(ctx, item, true)
					break
				case 'unarchive':
					await setArchived(ctx, item, false)
					break
				case 'delete':
					await deleteItem(ctx, item)
					break
				case 'discard':
					await discardItemDraft(ctx, item)
					break
			}
			outcomes.push({ item })
		} catch (e: any) {
			outcomes.push({ item, error: e?.body ?? e?.message ?? String(e) })

View on GitHub (pinned to e474e8803c)

Solutions

  1. Pass opts.target, e.g. runBulk(ctx, 'move', items, { workspace, target: 'folder/sub' }).
  2. Disable the Move button in the UI until a folder is selected.
  3. Guard in the caller: if (!target) return before invoking runBulk.
  4. Use a folder picker component that cannot resolve to an empty path.

Example fix

// before
await runBulk(ctx, 'move', items, { workspace })
// after
await runBulk(ctx, 'move', items, { workspace, target: selectedFolder })
Defensive patterns

Strategy: validation

Validate before calling

if (action === 'move' && !opts?.target) throw new Error('Select a destination folder first')

Type guard

function hasTarget(o) { return typeof o?.target === 'string' && o.target.length > 0 }

Try / catch

try { await runBulk(ctx, 'move', items, opts) } catch (e) { if (e.message === 'no target folder') openFolderPicker(); else throw e }

Prevention

When it happens

Trigger: Calling runBulk('move', items, opts) with opts.target undefined/null — e.g. the UI move dialog was dismissed or the folder picker returned nothing.

Common situations: Button wired to 'move' before the user selected a destination folder; programmatic use passing only { workspace }; target cleared by form reset.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


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