-
Notifications
You must be signed in to change notification settings - Fork 817
Description
Description
When running tests in CI mode (CI=true), the test harness proxy crashes with ERR_HTTP_HEADERS_SENT if a test triggers a request that has no cached response in the snapshot file.
This causes cascading test failures because the proxy process dies and subsequent tests cannot communicate with it.
Root Cause
In test/harness/replayingCapiProxy.ts around line 288-296, there is a missing return statement after calling exitWithNoMatchingRequestError():
// Fallback to normal proxying if no cached response found
// This implicitly captures the new exchange too
if (process.env.CI === "true") {
await exitWithNoMatchingRequestError(
options,
state.testInfo,
state.workDir,
state.toolResultNormalizers,
);
}
super.performRequest(options); // <-- This still executes after exitWithNoMatchingRequestError!The issue is that exitWithNoMatchingRequestError() calls options.onError() which writes HTTP headers and ends the response. But execution continues to super.performRequest(options), which also attempts to write HTTP headers, causing:
Error [ERR_HTTP_HEADERS_SENT]: Cannot write headers after they are sent to the client
This crashes the Node.js process entirely.
Reproduction
- Create a test that expects a timeout (like
sendAndWait throws on timeout) - The snapshot file intentionally has no assistant response
- Run the test in CI mode:
CI=true npm test - The proxy crashes, and any tests running after this one fail
Suggested Fix
Add return; after the exitWithNoMatchingRequestError() call:
if (process.env.CI === "true") {
await exitWithNoMatchingRequestError(
options,
state.testInfo,
state.workDir,
state.toolResultNormalizers,
);
return; // <-- Add this line
}
super.performRequest(options);Impact
This bug is why the sendAndWait throws on timeout test is currently skipped in CI (it.skipIf(process.env.CI === "true")). With this fix, that test could potentially be enabled in CI.
Workaround
In the Java SDK implementation, we worked around this by adding an HTTP health check to detect when the proxy has crashed and automatically restart it before the next test runs. However, fixing the root cause in the harness would be cleaner.
Environment
- Node.js: v22+
- Discovered while implementing the Java SDK for copilot-sdk