Skip to content

Commit df206bf

Browse files
fix: safeguard SSE error writes against closed sockets
1 parent e2af678 commit df206bf

1 file changed

Lines changed: 24 additions & 14 deletions

File tree

src/CopilotApiGateway.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,8 +2516,10 @@ export class CopilotApiGateway implements vscode.Disposable {
25162516
if (cts.token.isCancellationRequested) { return; }
25172517
console.error('Google streaming error:', error);
25182518
const apiError = error instanceof ApiError ? error : new ApiError(500, error.message || 'Internal Server Error', 'server_error');
2519-
res.write(JSON.stringify({ error: { code: apiError.status, message: apiError.message, status: apiError.code } }));
2520-
res.end();
2519+
if (!res.writableEnded && !res.destroyed) {
2520+
res.write(JSON.stringify({ error: { code: apiError.status, message: apiError.message, status: apiError.code } }));
2521+
res.end();
2522+
}
25212523
} finally {
25222524
cts.dispose();
25232525
}
@@ -2739,8 +2741,10 @@ export class CopilotApiGateway implements vscode.Disposable {
27392741
responseHeaders: res.getHeaders()
27402742
});
27412743
}
2742-
res.write(`event: error\ndata: ${JSON.stringify({ type: 'error', error: { type: apiError.code || 'api_error', message: apiError.message } })}\n\n`);
2743-
res.end();
2744+
if (!res.writableEnded && !res.destroyed) {
2745+
res.write(`event: error\ndata: ${JSON.stringify({ type: 'error', error: { type: apiError.code || 'api_error', message: apiError.message } })}\n\n`);
2746+
res.end();
2747+
}
27442748
} finally {
27452749
clearInterval(heartbeat);
27462750
cts.dispose();
@@ -3008,15 +3012,18 @@ export class CopilotApiGateway implements vscode.Disposable {
30083012
});
30093013
}
30103014
} catch (error) {
3015+
if (cts.token.isCancellationRequested) { return; }
30113016
const errorChunk = {
30123017
error: {
30133018
message: error instanceof Error ? error.message : 'Unknown error',
30143019
type: error instanceof ApiError ? error.type : 'server_error',
30153020
code: error instanceof ApiError ? error.code : undefined
30163021
}
30173022
};
3018-
res.write(`data: ${JSON.stringify(errorChunk)}\n\n`);
3019-
res.end();
3023+
if (!res.writableEnded && !res.destroyed) {
3024+
res.write(`data: ${JSON.stringify(errorChunk)}\n\n`);
3025+
res.end();
3026+
}
30203027

30213028
// Log error for streaming request
30223029
if (logRequestId && logRequestStart) {
@@ -3472,12 +3479,13 @@ export class CopilotApiGateway implements vscode.Disposable {
34723479
if (cts.token.isCancellationRequested) { return; }
34733480
console.error('Responses API streaming error:', error);
34743481
const apiError = error instanceof ApiError ? error : new ApiError(500, error.message || 'Internal Server Error', 'api_error');
3475-
res.write(`event: error\ndata: ${JSON.stringify({
3476-
type: 'error',
3477-
error: { type: apiError.type, message: apiError.message, code: apiError.code }
3478-
})
3479-
}\n\n`);
3480-
res.end();
3482+
if (!res.writableEnded && !res.destroyed) {
3483+
res.write(`event: error\ndata: ${JSON.stringify({
3484+
type: 'error',
3485+
error: { type: apiError.type, message: apiError.message, code: apiError.code }
3486+
})}\n\n`);
3487+
res.end();
3488+
}
34813489
} finally {
34823490
clearInterval(heartbeat);
34833491
cts.dispose();
@@ -4237,8 +4245,10 @@ export class CopilotApiGateway implements vscode.Disposable {
42374245
if (cts.token.isCancellationRequested) { return; }
42384246
console.error('Completions streaming error:', error);
42394247
const apiError = error instanceof ApiError ? error : new ApiError(500, error.message || 'Internal Server Error', 'api_error');
4240-
res.write(`data: ${JSON.stringify({ error: { message: apiError.message, type: apiError.type, code: apiError.code } })} \n\n`);
4241-
res.end();
4248+
if (!res.writableEnded && !res.destroyed) {
4249+
res.write(`data: ${JSON.stringify({ error: { message: apiError.message, type: apiError.type, code: apiError.code } })} \n\n`);
4250+
res.end();
4251+
}
42424252
} finally {
42434253
cts.dispose();
42444254
}

0 commit comments

Comments
 (0)