Skip to content

Commit af2fd9d

Browse files
authored
fix: should return 400 in image optimization when Next passes errorMessage (opennextjs#830)
* fix: should return 400 in image optimization when next passes an errorMessage * rm content-type * refactor test * lint * review * fixup * changeset
1 parent 741b539 commit af2fd9d

File tree

3 files changed

+39
-13
lines changed

3 files changed

+39
-13
lines changed

.changeset/unlucky-shrimps-lick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/aws": patch
3+
---
4+
5+
fix: return 400 when validateImageParams from Next passes an errorMessage

packages/open-next/src/adapters/image-optimization-adapter.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ export async function defaultHandler(
7979
headers,
8080
queryString === null ? undefined : queryString,
8181
);
82+
// We return a 400 here if imageParams returns an errorMessage
83+
// https://github.com/vercel/next.js/blob/512d8283054407ab92b2583ecce3b253c3be7b85/packages/next/src/server/next-server.ts#L937-L941
84+
if ("errorMessage" in imageParams) {
85+
error(
86+
"Error during validation of image params",
87+
imageParams.errorMessage,
88+
);
89+
return buildFailureResponse(
90+
imageParams.errorMessage,
91+
options?.streamCreator,
92+
400,
93+
);
94+
}
8295
let etag: string | undefined;
8396
// We don't cache any images, so in order to be able to return 304 responses, we compute an ETag from what is assumed to be static
8497
if (process.env.OPENNEXT_STATIC_ETAG) {
@@ -99,10 +112,13 @@ export async function defaultHandler(
99112
nextConfig,
100113
downloadHandler,
101114
);
102-
103115
return buildSuccessResponse(result, options?.streamCreator, etag);
104116
} catch (e: any) {
105-
return buildFailureResponse(e, options?.streamCreator);
117+
error("Failed to optimize image", e);
118+
return buildFailureResponse(
119+
"Internal server error",
120+
options?.streamCreator,
121+
);
106122
}
107123
}
108124

@@ -124,9 +140,6 @@ function validateImageParams(
124140
false,
125141
);
126142
debug("image params", imageParams);
127-
if ("errorMessage" in imageParams) {
128-
throw new Error(imageParams.errorMessage);
129-
}
130143
return imageParams;
131144
}
132145

@@ -182,34 +195,33 @@ function buildSuccessResponse(
182195
}
183196

184197
function buildFailureResponse(
185-
e: any,
198+
errorMessage: string,
186199
streamCreator?: StreamCreator,
200+
statusCode = 500,
187201
): InternalResult {
188-
debug(e);
202+
debug(errorMessage, statusCode);
189203
if (streamCreator) {
190204
const response = new OpenNextNodeResponse(
191205
() => void 0,
192206
async () => void 0,
193207
streamCreator,
194208
);
195-
response.writeHead(500, {
209+
response.writeHead(statusCode, {
196210
Vary: "Accept",
197211
"Cache-Control": "public,max-age=60,immutable",
198-
"Content-Type": "application/json",
199212
});
200-
response.end(e?.message || e?.toString() || "An error occurred");
213+
response.end(errorMessage);
201214
}
202215
return {
203216
type: "core",
204217
isBase64Encoded: false,
205-
statusCode: 500,
218+
statusCode: statusCode,
206219
headers: {
207220
Vary: "Accept",
208221
// For failed images, allow client to retry after 1 minute.
209222
"Cache-Control": "public,max-age=60,immutable",
210-
"Content-Type": "application/json",
211223
},
212-
body: toReadableStream(e?.message || e?.toString() || "An error occurred"),
224+
body: toReadableStream(errorMessage),
213225
};
214226
}
215227

packages/tests-e2e/tests/appRouter/image-optimization.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ test("Image Optimization", async ({ page }) => {
1818
await expect(el).toHaveJSProperty("complete", true);
1919
await expect(el).not.toHaveJSProperty("naturalWidth", 0);
2020
});
21+
22+
test("should return 400 when validateParams returns an errorMessage", async ({
23+
request,
24+
}) => {
25+
const res = await request.get("/_next/image");
26+
expect(res.status()).toBe(400);
27+
expect(res.headers()["cache-control"]).toBe("public,max-age=60,immutable");
28+
expect(await res.text()).toBe(`"url" parameter is required`);
29+
});

0 commit comments

Comments
 (0)