moeru-ai/airi · error · Error
id is required to remove a widget.
Error message
id is required to remove a widget.
What it means
Thrown by executeWidgetAction when action='remove' but no widget id can be resolved. The guard at widgets.ts:291 mirrors the update guard: normalizedId (trimmed id) must be truthy because removeWidget IPC targets exactly one widget by id. Unlike 'clear', 'remove' cannot operate without an identifier.
Source
Thrown at apps/stage-tamagotchi/src/renderer/stores/tools/builtin/widgets.ts:291
case 'update': {
if (!normalizedId)
throw new Error('id is required to update a widget.')
const componentProps = normalizeComponentProps(input.componentProps)
const sanitizedComponentProps = sanitizeComponentPropsForDispatch(input.componentName, componentProps)
const windowSize = resolveWindowSize(input.componentName, sanitizedComponentProps, input.windowSize)
await invokers.updateWidget({
id: normalizedId,
componentProps: sanitizedComponentProps,
...(input.alwaysOnTop === undefined ? {} : { alwaysOnTop: input.alwaysOnTop }),
...(windowSize === undefined ? {} : { windowSize }),
})
return `Updated widget (${normalizedId}).`
}
case 'remove': {
if (!normalizedId)
throw new Error('id is required to remove a widget.')
await invokers.removeWidget({ id: normalizedId })
return `Removed widget (${normalizedId}).`
}
case 'clear': {
await invokers.clearWidgets()
return 'Cleared all widgets.'
}
case 'open': {
const id = await invokers.prepareWindow(normalizedId ? { id: normalizedId } : {})
await invokers.openWindow(normalizedId ? { id: normalizedId } : {})
return `Opened widget window${id ? ` (${id})` : ''}.`
}
default:
return 'No action performed.'
}
}
View on GitHub (pinned to 27111382b4)
Solutions
- Pass the specific widget id to remove.
- If the intent is to remove all widgets, use action: 'clear' instead, which takes no id.
- Track spawned widget ids in caller state so remove always has a concrete target.
Example fix
// before
await executeWidgetAction({ action: 'remove', id: '' })
// after
await executeWidgetAction({ action: 'remove', id: 'w1' }) Defensive patterns
Strategy: validation
Validate before calling
const normalizedId = input.id?.trim()
if (input.action === 'remove' && !normalizedId)
throw new Error('id is required to remove a widget.')
// if intending to remove all, use action: 'clear' Type guard
function hasRemoveId(input) {
return input.action !== 'remove' || Boolean(input.id?.trim())
} Try / catch
try {
await executeWidgetAction(input)
} catch (e) {
if (e.message.includes('id is required to remove'))
// either supply the id or switch to action: 'clear'
throw e
} Prevention
- Distinguish single-widget remove from clear-all at the call site.
- Track live widget ids so remove always has a valid target.
When it happens
Trigger: Calling executeWidgetAction({ action: 'remove' }) with id omitted, empty, or whitespace. An LLM tool-call selecting remove but failing to carry the widget id forward.
Common situations: Confusing 'remove' (single widget by id) with 'clear' (all widgets) and omitting id; losing the id between spawn and remove turns in an agent conversation.
Related errors
- componentName is required to spawn a widget.
- id is required to update a widget.
- Invalid Godot stage scene input payload.
- timeout must be a positive finite number
- Failed to apply server channel configuration
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/f1768dd918d818f8.
Report an issue: GitHub.