moeru-ai/airi · error · Error
Gamelet `${bindingId}` is not open.
Error message
Gamelet `${bindingId}` is not open. What it means
Thrown by the gamelet orchestration request() handler when widgetsManager.getWidgetSnapshot(bindingId) returns a falsy value, meaning no widget window is currently open for that binding id. The request path relies on an open iframe to route messages to, so calling request before openWindow (or after close) is invalid.
Source
Thrown at apps/stage-tamagotchi/src/main/services/airi/plugins/kits/gamelet/orchestration.ts:59
await widgetsManager.pushWidget({
id: bindingId,
componentName: 'extension-ui',
componentProps,
size: 'l',
})
}
await widgetsManager.openWindow({ id: bindingId })
},
async configure(bindingId, payload) {
await widgetsManager.updateWidget({
id: bindingId,
componentProps: createComponentProps(bindingId, payload),
})
},
async request<TResponse = HostDataRecord>(bindingId: string, payload: HostDataRecord, options?: { timeoutMs?: number }): Promise<TResponse> {
if (!widgetsManager.getWidgetSnapshot(bindingId)) {
throw new Error(`Gamelet \`${bindingId}\` is not open.`)
}
return await widgetsManager.requestWidgetIframe<TResponse & Record<string, unknown>>(
bindingId,
payload,
{
timeoutMs: options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
},
) as TResponse
},
async close(bindingId) {
await widgetsManager.removeWidget(bindingId)
},
async isOpen(bindingId) {
return Boolean(widgetsManager.getWidgetSnapshot(bindingId))
},
dispose() {},
}View on GitHub (pinned to 27111382b4)
Solutions
- Call open(bindingId) (openWindow) and await its completion before issuing any request to that bindingId.
- Guard each request with a snapshot existence check and re-open the widget if it is missing.
- Verify the bindingId used in request exactly matches the id used in open.
- If the widget may have been closed, listen for the close/removal event and cancel or re-establish pending requests.
Example fix
// before
const result = await orchestration.request(bindingId, payload)
// after
if (!widgetsManager.getWidgetSnapshot(bindingId)) {
await orchestration.open(bindingId)
}
const result = await orchestration.request(bindingId, payload) Defensive patterns
Strategy: validation
Validate before calling
// Ensure the gamelet widget is open before requesting
if (!widgetsManager.getWidgetSnapshot(bindingId)) {
await orchestration.open(bindingId)
}
const result = await orchestration.request(bindingId, payload) Type guard
function isGameletOpen(bindingId: string, mgr: { getWidgetSnapshot: (id: string) => unknown }): boolean {
return Boolean(mgr.getWidgetSnapshot(bindingId))
} Try / catch
try {
return await orchestration.request(bindingId, payload, options)
} catch (e) {
if (/is not open/.test(errorMessageFrom(e) ?? '')) {
await orchestration.open(bindingId)
return await orchestration.request(bindingId, payload, options)
}
throw e
} Prevention
- Await open(bindingId) before issuing requests to that binding.
- Cancel pending requests when the widget close event fires.
- Encapsulate open-then-request in a single helper so callers can't skip the open step.
When it happens
Trigger: A gamelet host calls request(bindingId, payload) without first calling open(bindingId), or after the widget was closed/removed. Also happens if openWindow was called but the widget snapshot isn't ready yet (not yet registered in widgetsManager).
Common situations: Lifecycle ordering bug — request fired before the open promise resolved; the widget crashed and was auto-removed; the bindingId passed to request differs from the one passed to open; the widget was closed by user action while a queued request was in flight.
Related errors
- Godot stage is not running.
- Godot stage bridge is not connected.
- Failed to apply server channel configuration
- Invalid Godot stage scene input payload.
- Previous Godot stage process is still shutting down. Retry a
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/d4b95a9902fdf238.
Report an issue: GitHub.