add more edge cases to Query Error parser (#2003)

This commit is contained in:
Ashley Stanton-Nurse 2024-10-30 08:43:18 -07:00 committed by GitHub
parent b93c90e7d1
commit 056be2a74d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 8 deletions

View File

@ -36,7 +36,7 @@ describe("QueryError.tryParse", () => {
code: "BadRequest", code: "BadRequest",
message: "Your query is bad, and you should feel bad", message: "Your query is bad, and you should feel bad",
}; };
const message = JSON.stringify(innerError); const message = `Message: ${JSON.stringify(innerError)}\r\nActivity ID: 42`;
const outerError = { const outerError = {
code: "BadRequest", code: "BadRequest",
message, message,
@ -48,7 +48,7 @@ describe("QueryError.tryParse", () => {
]); ]);
}); });
// Imitate the value coming from the backend, which has the syntax errors serialized as JSON in the message. // Imitate the value coming from the backend, which has the syntax errors serialized as JSON in the message, along with a prefix and activity id.
it("handles single-nested error", () => { it("handles single-nested error", () => {
const errors = [ const errors = [
{ {
@ -69,7 +69,7 @@ describe("QueryError.tryParse", () => {
message: "Your query is bad, and you should feel bad", message: "Your query is bad, and you should feel bad",
errors, errors,
}; };
const message = JSON.stringify(innerError); const message = `Message: ${JSON.stringify(innerError)}\r\nActivity ID: 42`;
const outerError = { const outerError = {
code: "BadRequest", code: "BadRequest",
message, message,
@ -91,4 +91,23 @@ describe("QueryError.tryParse", () => {
), ),
]); ]);
}); });
// Imitate another value we've gotten from the backend, which has a doubly-nested JSON payload.
it("handles double-nested error", () => {
const outerError = {
code: "BadRequest",
message:
'{"code":"BadRequest","message":"{\\"errors\\":[{\\"severity\\":\\"Error\\",\\"location\\":{\\"start\\":7,\\"end\\":18},\\"code\\":\\"SC2005\\",\\"message\\":\\"\'nonexistent\' is not a recognized built-in function name.\\"}]}\\r\\nActivityId: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa, Windows/10.0.20348 cosmos-netstandard-sdk/3.18.0"}',
};
const result = QueryError.tryParse(outerError, testErrorLocationResolver);
expect(result).toEqual([
new QueryError(
"'nonexistent' is not a recognized built-in function name.",
QueryErrorSeverity.Error,
"SC2005",
new QueryErrorLocation({ offset: 7, lineNumber: 7, column: 7 }, { offset: 18, lineNumber: 18, column: 18 }),
),
]);
});
}); });

View File

@ -214,16 +214,28 @@ export default class QueryError {
return null; return null;
} }
// Assign to a new variable because of a TypeScript flow typing quirk, see below. // Some newer backends produce a message that contains a doubly-nested JSON payload.
if (message.startsWith("Message: ")) { // In this case, the message we get is a fully-complete JSON object we can parse.
// Reassigning this to 'error' restores the original type of 'error', which is 'unknown'. // So let's try that first
// So we use a separate variable to avoid this. if (message.startsWith("{") && message.endsWith("}")) {
message = message.substring("Message: ".length); let outer: unknown = undefined;
try {
outer = JSON.parse(message);
if (typeof outer === "object" && "message" in outer && typeof outer.message === "string") {
message = outer.message;
}
} catch (e) {
// Just continue if the parsing fails. We'll use the fallback logic below.
}
} }
const lines = message.split("\n"); const lines = message.split("\n");
message = lines[0].trim(); message = lines[0].trim();
if (message.startsWith("Message: ")) {
message = message.substring("Message: ".length);
}
let parsed: unknown; let parsed: unknown;
try { try {
parsed = JSON.parse(message); parsed = JSON.parse(message);