From e9f05bf8fb82bfe9e18ca4134d5a37bb471f844d Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Wed, 26 Aug 2026 22:42:44 +0000 Subject: [PATCH 1/2] fix(api-client): Use ApiClientError for non-JSON 400 responses --- packages/mcp-core/src/api-client/client.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/mcp-core/src/api-client/client.ts b/packages/mcp-core/src/api-client/client.ts index 3151c0dbe..a3ffb4e89 100644 --- a/packages/mcp-core/src/api-client/client.ts +++ b/packages/mcp-core/src/api-client/client.ts @@ -883,15 +883,21 @@ export class SentryApiService { responseText.includes(" Date: Wed, 23 Sep 2026 16:24:16 +0000 Subject: [PATCH 2/2] test(api-client): cover non-JSON validation errors --- .../mcp-core/src/api-client/client.test.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/packages/mcp-core/src/api-client/client.test.ts b/packages/mcp-core/src/api-client/client.test.ts index bd41cdbbe..868345e7b 100644 --- a/packages/mcp-core/src/api-client/client.test.ts +++ b/packages/mcp-core/src/api-client/client.test.ts @@ -3,6 +3,56 @@ import { http, HttpResponse } from "msw"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { ConfigurationError } from "../errors"; import { SentryApiService } from "./client"; +import { ApiClientError, ApiValidationError } from "./errors"; + +describe("validateEvents non-JSON responses", () => { + afterEach(() => mswServer.resetHandlers()); + + it.each(["text/plain", "text/html"])( + "classifies a 400 %s response as a client error", + async (contentType) => { + mswServer.use( + http.get( + "https://sentry.io/api/0/organizations/test-org/events/validate/", + () => + new HttpResponse("Invalid query", { + status: 400, + headers: { "Content-Type": contentType }, + }), + ), + ); + const api = new SentryApiService({ + host: "sentry.io", + accessToken: "test-token", + }); + await expect( + api.validateEvents({ organizationSlug: "test-org" }), + ).rejects.toBeInstanceOf(ApiValidationError); + }, + ); + + it("does not classify a successful HTML response as user input", async () => { + mswServer.use( + http.get( + "https://sentry.io/api/0/organizations/test-org/events/validate/", + () => + new HttpResponse("Unexpected response", { + status: 200, + headers: { "Content-Type": "text/html" }, + }), + ), + ); + const api = new SentryApiService({ + host: "sentry.io", + accessToken: "test-token", + }); + const result = api.validateEvents({ organizationSlug: "test-org" }); + await expect(result).rejects.toThrow( + "Expected JSON response but received HTML", + ); + await expect(result).rejects.not.toBeInstanceOf(ApiClientError); + }); +}); describe("getIssueUrl", () => { it("should work with sentry.io", () => {