diff --git a/src/core/source/GitHubStream.ts b/src/core/source/GitHubStream.ts index 4a877d2..efc5cf6 100644 --- a/src/core/source/GitHubStream.ts +++ b/src/core/source/GitHubStream.ts @@ -291,14 +291,23 @@ export default class GitHubStream extends GitHubBase { ?.statusCode ?? (error as { status?: number })?.status ?? (error as { httpStatus?: number })?.httpStatus; + const errCode = (error as { code?: string })?.code; + const isTransient = + !httpStatus && + (errCode === "ECONNRESET" || + errCode === "ETIMEDOUT" || + errCode === "ERR_BODY_PARSE_FAILURE" || + error.name === "ReadError"); const code = httpStatus === 422 ? "file_too_big" : httpStatus === 403 ? "file_not_accessible" + : isTransient + ? "upstream_error" : "file_not_found"; const wrapped = new AnonymousError(code, { - httpStatus, + httpStatus: isTransient ? 502 : httpStatus, cause: error as Error, object: filePath, }); diff --git a/src/streamer/route.ts b/src/streamer/route.ts index ea9dfcc..1c3faec 100644 --- a/src/streamer/route.ts +++ b/src/streamer/route.ts @@ -108,6 +108,7 @@ router.post("/", async (req: express.Request, res: express.Response) => { content .on("error", handleStreamError) .pipe(anonymizer) + .on("error", handleStreamError) .pipe(res) .on("error", handleStreamError) .on("close", () => { diff --git a/test/route-utils-handleError.test.js b/test/route-utils-handleError.test.js index 160dbfe..895d615 100644 --- a/test/route-utils-handleError.test.js +++ b/test/route-utils-handleError.test.js @@ -53,14 +53,14 @@ describe("route-utils.handleError", function () { }); handleError(err, res); expect(res.statusCode).to.equal(503); - expect(res.body).to.deep.equal({ error: "S3 down" }); + expect(res.body).to.deep.equal({ error: "internal_error" }); }); it("maps messages containing 'not_found' to 404", function () { const res = makeRes(); handleError(new Error("repo_not_found"), res); expect(res.statusCode).to.equal(404); - expect(res.body).to.deep.equal({ error: "repo_not_found" }); + expect(res.body).to.deep.equal({ error: "internal_error" }); }); it("maps messages containing '(Not Found)' (got HTTPError style) to 404", function () { @@ -73,21 +73,21 @@ describe("route-utils.handleError", function () { const res = makeRes(); handleError(new Error("user_not_connected"), res); expect(res.statusCode).to.equal(401); - expect(res.body).to.deep.equal({ error: "user_not_connected" }); + expect(res.body).to.deep.equal({ error: "internal_error" }); }); it("defaults to 500 when nothing matches", function () { const res = makeRes(); handleError(new Error("kaboom"), res); expect(res.statusCode).to.equal(500); - expect(res.body).to.deep.equal({ error: "kaboom" }); + expect(res.body).to.deep.equal({ error: "internal_error" }); }); it("accepts a string error and stringifies it in the body", function () { const res = makeRes(); handleError("something_bad", res); expect(res.statusCode).to.equal(500); - expect(res.body).to.deep.equal({ error: "something_bad" }); + expect(res.body).to.deep.equal({ error: "internal_error" }); }); it("does not call res when headersSent is true", function () {