moeru-ai/airi · error · Error
Computer use has stopped.
Error message
Computer use has stopped.
What it means
enqueue serializes operations on a promise queue. Each queued operation re-checks the disposed flag just before running, so commands accepted before dispose but not yet executed still fail with this error instead of hitting a dead daemon.
Solutions
- Await in-flight run/readImage promises before calling dispose
- Guard callers with a stopped/cancelled check before enqueueing
- Catch this error and treat it as a cancellation, not a command failure
Example fix
// before
const result = await runtime.run(input) // may be disposed mid-queue
// after
try {
const result = await runtime.run(input)
} catch (e) {
if (e.message.includes('has stopped')) return cancelledResult
throw e
} Defensive patterns
Strategy: retry
Validate before calling
// Wait for queued work before disposing await Promise.race([pendingOperations, timeout(5000)])
Try / catch
try {
return await runtime.run(input)
} catch (e) {
if (e instanceof Error && e.message.includes('Computer use has stopped')) {
// treat as cancellation; optionally re-setup and retry once
return cancelled
}
throw e
} Prevention
- Serialize all run/readImage calls through a single owner so you know when the queue is empty
- Await all in-flight promises before dispose
- On shutdown, first reject new requests, then drain, then dispose
When it happens
Trigger: Calling run() or readImage() while a prior operation is still in flight and dispose() runs before the queued operation's turn arrives.
Common situations: User quits/disables computer use while a long screenshot request is queued; dispose() during shutdown races pending AI tool calls.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Chat session was removed before send completed
- Computer use has stopped.
- Extension directory importer is disposed.
- Extension module ` ` is already registered for session .
- Extension package changed during copy. Select the folder…
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17).
Data as JSON: /api/errors/351b7e3ca0d3a005.
Report an issue: GitHub.
Appendix: source
Thrown at apps/stage-tamagotchi/src/main/services/airi/computer-use/runtime.ts:77
return started
}
catch (error) {
await cleanupSocket()
throw error
}
}
async function cleanupSocket() {
if (socketDirectory) {
await rm(socketDirectory, { recursive: true, force: true })
socketDirectory = undefined
}
}
function enqueue<T>(operation: () => Promise<T>): Promise<T> {
const next = queue.then(() => {
if (disposed)
throw new Error('Computer use has stopped.')
return operation()
})
// A failed command must not prevent later commands from running.
queue = next.then(() => undefined, () => undefined)
return next
}
async function run(input: unknown): Promise<ComputerUseResult> {
const { argv } = v.parse(inputSchema, input)
if (argv[0] !== 'invoke' || !/^(?:--help|-h|help|(?:app|display|screen|window|input|mediaControl)\.[a-zA-Z]+)$/.test(argv[1]))
throw new Error('Use invoke with a desktop command or --help.')
// The host owns routing and artifact storage. CLI global flags must not replace them.
const managedFlags = ['--store-root', '--endpoint', '--device', '--device-id', '--run', '--config', '--profile', '--discovery-file', '--pairing-store']
if (argv.some(arg => managedFlags.some(flag => arg === flag || arg.startsWith(`${flag}=`))))
throw new Error('Computer use routing and storage are managed by AIRI.')
return enqueue(async () => {View on GitHub (pinned to 438a067dde)