github/copilot-sdk · warning
Ignoring a background factory progress flush failure after…
Error message
Ignoring a background factory progress flush failure after the factory body settled
What it means
Not a thrown exception but a console warning emitted from close() (nodejs/src/session.ts:287): when the background factory-progress flush task (flushTail) previously failed (flushFailed set) while the session was streaming, close() awaits it and then logs this warning with the stored flushError. It tells the developer some progress events may not have been flushed, but close() continues deliberately and does not fail.
Solutions
- Check the accompanying flushError in the warning for the underlying stream failure
- Verify the destination stream/pipe stayed writable for the session's lifetime (file handle not closed early, pipe consumer alive)
- Drain/await pending progress lines before closing, or re-persist the lines pending at close()
- Treat the warning as a data-loss signal: re-send or log the unflushed progress events
Example fix
// before await session.close(); // flush failure only surfaces as a console warning // after if (session.flushFailed) await persistProgress(session.pendingLines); await session.close();
Defensive patterns
Strategy: try-catch
Validate before calling
// before close, ensure the stream is still writable
if (session.outputStream.destroyed || session.outputStream.writableEnded) {
console.warn('Progress output stream already closed; progress may be lost');
} Type guard
function hasFlushError(s) {
return s.flushFailed === true && s.flushError instanceof Error;
} Try / catch
try {
await session.close();
} catch (err) {
console.error('close failed', err); // the flush warning itself is non-fatal
} finally {
if (session.flushFailed) persistProgress(session.pendingLines); // recover unflushed data
} Prevention
- Keep the destination stream open until after close() resolves
- Track flush errors (flushFailed/flushError) at runtime instead of relying on the console warning at close
- Periodically flush pending lines with a shorter timer so bursts do not accumulate
- Back up unflushed progress lines before closing if delivery guarantees matter
When it happens
Trigger: Calling session.close() after a background flush of pending factory progress lines already rejected asynchronously (stream errored, pipe broken, or disk full mid-flight), so this.flushFailed is true and this.flushError is set when close() awaits this.flushTail.
Common situations: Output stream (file/pipe/socket) was closed or broke while the session was still running; process exit raced a pending flush; disk-full or EPIPE caused a flush rejection and the timer-driven retry also failed.
Related errors
- Invalid off/len for buffer of length + b.length
- Failed to flush final factory progress after the factory…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/e172244cf0c90f46.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:287
this.flushFailed = true;
this.flushError = error;
}
}
});
}
await this.flushTail;
if (this.flushFailed) {
throw this.flushError;
}
}
async close(): Promise<void> {
this.closed = true;
this.clearFlushTimer();
const lines = this.pending.splice(0);
await this.flushTail;
if (this.flushFailed) {
console.warn(
"Ignoring a background factory progress flush failure after the factory body settled",
this.flushError
);
}
if (lines.length > 0) {
try {
await this.send(lines);
} catch (error) {
console.warn(
"Failed to flush final factory progress after the factory body settled",
error
);
}
}
}
private scheduleFlush(): void {
if (this.flushTimer !== undefined) {View on GitHub (pinned to cd8cf15dc3)