moeru-ai/airi · warning
[InferenceWorkerManager] Restarting worker in ${delay}ms (at
Error message
[InferenceWorkerManager] Restarting worker in ${delay}ms (attempt ${restartAttempts}/${maxRestarts}) What it means
Scheduled-restart notice from InferenceWorkerManager, the generic lifecycle wrapper for inference Web Workers in packages/stage-ui/src/libs/inference/worker-manager.ts. When the managed worker dies or fails terminally, scheduleRestart() re-spawns it via ensureStarted() with linear backoff (restartDelayMs multiplied by attempt number; defaults 1000ms base, 3 max attempts from WorkerManagerOptions). This line is only the retry announcement - the actual crash cause appears earlier in the console or on manager.lastError.
Source
Thrown at packages/stage-ui/src/libs/inference/worker-manager.ts:207
function destroyWorker(): void {
if (worker) {
worker.terminate()
worker = null
}
}
function scheduleRestart(): void {
if (restartAttempts >= maxRestarts) {
console.error(
`[InferenceWorkerManager] Max restart attempts (${maxRestarts}) reached. Giving up.`,
)
return
}
restartAttempts++
const delay = restartDelayMs * restartAttempts
console.warn(
`[InferenceWorkerManager] Restarting worker in ${delay}ms `
+ `(attempt ${restartAttempts}/${maxRestarts})`,
)
setTimeout(() => {
ensureStarted().catch((err) => {
console.error('[InferenceWorkerManager] Failed to restart:', errorMessageFrom(err))
})
}, delay)
}
function onSuccessfulOperation(): void {
restartAttempts = 0
}
async function ensureStarted(): Promise<void> {
await lifecycleMutex.runExclusive(async () => {
if (!worker) {View on GitHub (pinned to 677329427f)
Solutions
- Scroll up in the console for the originating worker error, or read manager.lastError - this log only reports the retry, not the cause
- If the log sequence ends with 'Max restart attempts reached', reproduce the worker failure directly and fix the root cause (model id, quantization, device support, import failure)
- Raise maxRestarts or restartDelayMs in the options passed to createInferenceWorkerManager when the crash is transient, e.g. a GPU reset during startup
- Reduce model size or quantization, or force device 'wasm', if the worker dies from OOM during load
- After the manager gives up (state 'error'), call terminate() and build a fresh manager instead of expecting automatic recovery
Example fix
// before
const manager = createInferenceWorkerManager({ createWorker })
// crash loop exhausts defaults: 3 attempts, 1s base delay
// after
const manager = createInferenceWorkerManager({
createWorker,
maxRestarts: 5,
restartDelayMs: 2_000, // backoff: 2s, 4s, 6s...
}) Defensive patterns
Strategy: retry
Validate before calling
if (manager.state !== 'ready' && manager.state !== 'running') {
await manager.loadModel({ modelId, device: 'wasm' })
} Type guard
function isUsableManager(m: InferenceWorkerManager): boolean {
return m.state === 'ready' || m.state === 'running'
} Try / catch
try {
await manager.run(input)
}
catch (err) {
if (manager.state === 'error' || manager.state === 'terminated') {
manager.terminate()
// rebuild the manager, then retry the operation once
}
else throw err
} Prevention
- Watch manager.state and manager.lastError programmatically instead of parsing console output
- Size models to the worker's memory budget so restarts are rare
- Treat repeated restart warnings as a crash loop - fix the underlying worker error rather than raising maxRestarts
- Test with the same device (webgpu/wasm) as production browsers
When it happens
Trigger: The worker exits unexpectedly (uncaught exception or out-of-memory inside the worker during transformers.js model load or inference), a loadModel/run request fails hard enough to trigger the restart path, or the browser tears the worker down. Each failure increments restartAttempts and logs 'Restarting worker in <delay>ms (attempt N/M)'. After maxRestarts failures the manager logs 'Max restart attempts reached. Giving up.' and stops.
Common situations: WebGPU device lost inside the worker, OOM when loading a large model, stale worker bundle after dev HMR, or a deterministic crash loop (bad model file, unsupported device, missing import) that burns all 3 attempts. Note the file header: no adapter currently consumes this manager, so seeing it means custom code built on it.
Related errors
- [KokoroAdapter] Restarting in ${delay}ms (attempt ${restartA
- [WhisperAdapter] Restarting in ${delay}ms (attempt ${restart
- MediaPipe backend not initialized (call init() first)
- gameletKit requires a host gamelet orchestration runtime.
- Extension module `${input.id}` is already registered for ses
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/079b3d6000e6e735.
Report an issue: GitHub.