tobi/qmd · error · SessionReleasedError
Session aborted
Error message
Session aborted
What it means
A queued session operation began executing after AbortController.abort() was already called. The wrapper re-checks the abort signal before invoking fn() and surfaces the abort reason (defaulting to 'Session aborted') as a SessionReleasedError.
Source
Thrown at src/llm.ts:2033
}
this.abortController.abort(new Error("Session released"));
this.manager.release();
}
/**
* Wrap an operation with tracking and abort checking.
*/
private async withOperation<T>(fn: () => Promise<T>): Promise<T> {
if (!this.isValid) {
throw new SessionReleasedError();
}
this.manager.operationStart();
try {
// Check abort before starting
if (this.abortController.signal.aborted) {
throw new SessionReleasedError(
this.abortController.signal.reason?.message || "Session aborted"
);
}
return await fn();
} finally {
this.manager.operationEnd();
}
}
async embed(text: string, options?: EmbedOptions): Promise<EmbeddingResult | null> {
return this.withOperation(() => this.manager.getLlamaCpp().embed(text, options));
}
async embedBatch(texts: string[], options?: EmbedOptions): Promise<(EmbeddingResult | null)[]> {
return this.withOperation(() => this.manager.getLlamaCpp().embedBatch(texts, options));
}
async expandQuery(View on GitHub (pinned to dbfd0b4736)
Solutions
- Check session liveness (not aborted/disposed) before submitting work and re-create the session if aborted
- Await or cancel pending operations before calling abort()/close()
- Propagate the abort reason and retry the operation on a fresh session
Example fix
// before const r = await session.run(fn); // may already be aborted // after if (session.abortController.signal.aborted) await recreateSession(); const r = await session.run(fn);
Defensive patterns
Strategy: retry
Validate before calling
if (session.abortController.signal.aborted) await recreateSession();
Type guard
const isSessionUsable = (s: Session) => !s.abortController.signal.aborted;
Try / catch
try { return await session.run(fn); } catch (e) { if (e instanceof SessionReleasedError) { await recreateSession(); return session.run(fn); } throw e; } Prevention
- Drain or cancel queued ops before abort/close
- Check signal.aborted before enqueueing
- Add timeouts so aborts don't race queued work
When it happens
Trigger: Calling a session operation (embed, generate, rerank) after session.close()/dispose() or explicit abort(); or a queued operation whose signal was aborted while it waited in the queue.
Common situations: Timeout logic that aborts the session while requests are still queued; concurrent callers racing with shutdown; idle-unload of models aborting in-flight queued work.
AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28).
Data as JSON: /api/errors/c599bb2eb07e23b6.
Report an issue: GitHub.