github/copilot-sdk · error
Cannot log after the factory run has settled
Error message
Cannot log after the factory run has settled
What it means
FactoryLogSink.enqueue (logger factory) queues log lines and flushes them on a 10ms delay while the factory run is live. Once the run has settled, closed is set to true and further logging is rejected — late logs could never be delivered and would silently vanish, so the library surfaces this instead.
Solutions
- Ensure all logging happens before the factory run's promises settle — await async work inside the thunk.
- Guard late log calls: capture the error and drop or buffer logs after settle.
- Move long-running background work outside the factory run, with its own lifecycle.
Example fix
// before
setTimeout(() => ctx.log("info", "done"), 100); // run already settled
// after
await new Promise((r) => setTimeout(r, 100));
ctx.log("info", "done"); Defensive patterns
Strategy: try-catch
Try / catch
try { ctx.log('info', 'done'); } catch (e) { if (String(e.message).includes('settled')) return; throw e; } Prevention
- Await all async work inside factory thunks; avoid fire-and-forget promises.
- Clear timers and unsubscribe event listeners when the run completes.
- Add a safeLog wrapper that no-ops after settle.
When it happens
Trigger: Invoking ctx.log (enqueue) after the factory run settled: fire-and-forget promises that resolve late, setTimeout/setInterval callbacks, or event listeners that survive past the run's completion.
Common situations: A thunk that starts a background fetch and logs its result after Promise.all resolved; debounced code logging on a timer that outlives the run; unawaited async work inside a factory.
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
- Client is not started. Call StartAsync first.
- CLI process not started
- CLI child process was unexpectedly started in parent…
- Server port not available
- Session not found
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/2913c8d3c126a4b3.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:253
return previous;
})
);
}
class FactoryProgressBuffer {
private nextSeq = 0;
private pending: FactoryLogLine[] = [];
private flushTimer?: ReturnType<typeof setTimeout>;
private flushTail: Promise<void> = Promise.resolve();
private flushError: unknown;
private flushFailed = false;
private closed = false;
constructor(private readonly send: (lines: FactoryLogLine[]) => Promise<void>) {}
enqueue(kind: FactoryLogLine["kind"], text: string): void {
if (this.closed) {
throw new Error("Cannot log after the factory run has settled");
}
this.pending.push({ seq: this.nextSeq++, kind, text });
this.scheduleFlush();
}
async flush(): Promise<void> {
this.clearFlushTimer();
const lines = this.pending.splice(0);
if (lines.length > 0) {
this.flushTail = this.flushTail.then(async () => {
try {
await this.send(lines);
} catch (error) {
if (!this.flushFailed) {
this.flushFailed = true;
this.flushError = error;
}View on GitHub (pinned to cd8cf15dc3)