fix(images): normalize image endpoint error format (#9981) (#10020)

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-08-10 11:18:14 -03:00
committed by GitHub
parent fed0858f89
commit aafdc4d4c6
4 changed files with 72 additions and 8 deletions

View File

@@ -0,0 +1 @@
- fix(images): normalize terminal upstream errors via OpenAI-standard type/code (#9981)

View File

@@ -308,10 +308,11 @@ async function postHandler(request, context) {
}
const errorPayload = toJsonErrorPayload((result as any).error, "Image generation provider error");
return new Response(JSON.stringify(errorPayload), {
status: (result as any).status,
headers: { "Content-Type": "application/json" },
});
const message =
typeof errorPayload?.error?.message === "string"
? errorPayload.error.message
: "Image generation provider error";
return errorResponse((result as any).status, message);
}
export const POST = withInjectionGuard(postHandler);

View File

@@ -119,8 +119,9 @@ export async function POST(request, { params }) {
}
const errorPayload = toJsonErrorPayload((result as any).error, "Image generation provider error");
return new Response(JSON.stringify(errorPayload), {
status: (result as any).status,
headers: { "Content-Type": "application/json" },
});
const message =
typeof errorPayload?.error?.message === "string"
? errorPayload.error.message
: "Image generation provider error";
return errorResponse((result as any).status, message);
}

View File

@@ -701,6 +701,67 @@ test("provider-scoped image generation POST uses the shared 401 account fallback
]);
});
test("v1 image generation POST normalizes a terminal upstream 401 to the OpenAI-standard error shape", async () => {
await seedConnection("openai", { apiKey: "single-expired-image-key" });
globalThis.fetch = async (url, options: RequestInit = {}) => {
assert.equal(String(url), "https://api.openai.com/v1/images/generations");
const authorization = new Headers(options.headers).get("authorization") ?? "";
assert.equal(authorization, "Bearer single-expired-image-key");
return new Response(JSON.stringify({ error: { message: "expired access token" } }), {
status: 401,
headers: { "content-type": "application/json" },
});
};
const response = await imageRoute.POST(
new Request("http://localhost/api/v1/images/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ model: "openai/gpt-image-2", prompt: "normalize terminal 401" }),
})
);
const body = (await response.json()) as ErrorResponseBody;
assert.equal(response.status, 401);
assert.deepEqual(body.error, {
message: "expired access token",
type: "authentication_error",
code: "invalid_api_key",
});
});
test("provider-scoped image generation POST normalizes a terminal upstream 401 to the OpenAI-standard error shape", async () => {
await seedConnection("openai", { apiKey: "provider-single-expired-key" });
globalThis.fetch = async (url, options: RequestInit = {}) => {
assert.equal(String(url), "https://api.openai.com/v1/images/generations");
const authorization = new Headers(options.headers).get("authorization") ?? "";
assert.equal(authorization, "Bearer provider-single-expired-key");
return new Response(JSON.stringify({ error: { message: "expired provider token" } }), {
status: 401,
headers: { "content-type": "application/json" },
});
};
const response = await providerImageRoute.POST(
new Request("http://localhost/api/v1/providers/openai/images/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ model: "gpt-image-2", prompt: "normalize provider terminal 401" }),
}),
{ params: Promise.resolve({ provider: "openai" }) }
);
const body = (await response.json()) as ErrorResponseBody;
assert.equal(response.status, 401);
assert.deepEqual(body.error, {
message: "expired provider token",
type: "authentication_error",
code: "invalid_api_key",
});
});
test("v1 image generation POST refreshes an expired Antigravity token before dispatch", async () => {
await seedConnection("antigravity", {
authType: "oauth",