-
Notifications
You must be signed in to change notification settings - Fork 757
Open
Labels
Description
Issue Description
Error: Execution failed: request ended without sending any chunks
Context
- Tool: GitHub Copilot CLI (terminal agent)
- Session: Long-running interactive session
- Trigger: Tool execution (bash/file operations) interrupted mid-stream
- Impact: Abrupt termination with no partial output, unclear session state
Expected Behavior
- Proper timeout handling with configurable limits
- Graceful degradation when stream fails
- Buffer partial responses before streaming begins
- Clear error messages with actionable context
- Automatic retry with exponential backoff
Actual Behavior
- Abrupt termination with generic error message
- No partial output preserved or accessible
- Session state unclear after error
- No retry mechanism offered
- User forced to restart conversation
Reproduction Steps
- Start long-running Copilot CLI session
- Execute complex tool operation (e.g., file operations, bash commands)
- Network hiccup or API timeout occurs mid-stream
- Observe generic "request ended without sending any chunks" error
Suggested Fix
// Add stream buffering and timeout guards
async function executeToolWithRetry(tool, params, options = {}) {
const { timeout = 120000, maxRetries = 3, backoff = 2000 } = options;
const buffer = [];
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const stream = await tool.execute(params);
// Buffer initial chunks before streaming to user
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
);
for await (const chunk of stream) {
buffer.push(chunk);
if (buffer.length >= 3) break; // Buffer first 3 chunks
}
// Stream rest to user
for (const chunk of buffer) yield chunk;
for await (const chunk of stream) yield chunk;
return; // Success
} catch (error) {
if (attempt === maxRetries) {
// Provide buffered content even on failure
if (buffer.length > 0) {
yield "⚠️ Partial result (connection interrupted):\n";
for (const chunk of buffer) yield chunk;
}
throw new Error(\`Failed after \${maxRetries} attempts: \${error.message}\`);
}
await new Promise(resolve => setTimeout(resolve, backoff * attempt));
}
}
}Environment
- OS: Linux (Fedora)
- Node.js: v22.20.0
- Copilot CLI: Running as daemon process
- Session type: Interactive terminal
Reported by: Roger Luft
Email: [email protected]
Research: https://fcc.rogerluft.com.br
Date: 2025-11-21
alkanen