hcengineering/platform · error
Action requires at least one document
Error message
Action requires at least one document
What it means
anyActionWithAvailability wraps an action that accepts one or many documents. Its action() throws Error('Action requires at least one document') when invoked with doc === undefined, i.e. no document/selection was passed at all. The 'any' variant requires a non-undefined input (unlike focus which demands exactly one, or eachItem which also rejects empty arrays).
Source
Thrown at plugins/questions-resources/src/actions/ActionWithAvailability.ts:75
await action(evt as E, params)
}
}
}
export function anyActionWithAvailability<T extends Doc, E extends Event = Event, P = never> (
isAvailable: (doc: T | T[]) => Promise<boolean>,
action: (doc: T | T[], event?: E, params?: P) => Promise<any>
): ActionWithAvailability<T, P> {
return {
isAvailable: async function (doc: T | T[] | undefined): Promise<boolean> {
if (doc === undefined) {
return false
}
return await isAvailable(doc)
},
action: async function (doc: T | T[] | undefined, evt?: Event, params?: P): Promise<void> {
if (doc === undefined) {
throw new Error('Action requires at least one document')
}
if (!(await isAvailable(doc))) {
throw new Error('Action not available')
}
await action(doc, evt as E, params)
}
}
}
/**
* A special case of `any` action that performs an individual independent operation on each item,
* and only if it is available for all items. Very opinionated about how to iterate items during
* availability check and action invocation.
*
* If you're building an action different from that, consider using a general purpose
* {@link anyActionWithAvailability()} and implementing your own iteration logic.
*
* @param isAvailableView on GitHub (pinned to 63e28dc964)
Solutions
- Check that the selection is defined and non-empty before invoking the action, and disable/hide the action UI otherwise
- Guard the call site: if (selection !== undefined) await action.action(selection, evt)
- Prefer using the action's isAvailable(doc) — it returns false for undefined — as a gate before calling action()
- Fix the wiring so the action is only triggered from UI contexts that guarantee a selection (e.g. row context menus, selection toolbar)
Example fix
// before
await deleteAction.action(selection, evt) // selection may be undefined
// after
if (selection === undefined) {
ui.notify('Select at least one item first')
return
}
await deleteAction.action(selection, evt) Defensive patterns
Strategy: validation
Validate before calling
if (selection === undefined) {
throw new SkipActionError('Select at least one document')
}
await actionObj.action(selection, evt) Type guard
function isDefined<T>(value: T | undefined): value is T {
return value !== undefined
} Try / catch
try {
await actionObj.action(selection, evt)
} catch (err) {
if (err instanceof Error && err.message === 'Action requires at least one document') {
ui.notify('Select at least one document first')
return
}
throw err
} Prevention
- Never pass selection state straight through without an undefined check
- Disable toolbar/shortcut actions when the selection is empty
- Favor UI entry points (context menus, selection toolbars) that guarantee a selection
- Use isAvailable(doc) as a cheap gate — it returns false for undefined
When it happens
Trigger: Calling action() on an action created by anyActionWithAvailability and passing undefined as the doc argument — typically when the UI selection is empty and the caller forwards it unguarded to the action.
Common situations: A bulk action (e.g. archive/delete selected items) invoked with nothing selected; a keyboard shortcut or toolbar button wired to the action without disabling it for empty selections; custom code reading a selection from state that defaults to undefined before any item is picked.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/de21fd49e91507d5.
Report an issue: GitHub.