From 0ea7ddbbdad949b7a8e7cee5c20e224572cf6940 Mon Sep 17 00:00:00 2001 From: Victor <70475442+vsolano9@users.noreply.github.com> Date: Sun, 23 Aug 2026 15:57:24 +0200 Subject: [PATCH] fix(scorer): report invalid schema patterns Catch JSON Schema pattern compilation failures and return a path-attributed validation error instead of aborting the evaluation run. Cover nested invalid patterns and preserve valid mismatch behavior. --- src/scorers/json-schema.ts | 11 +++++++++-- tests/scorers.test.ts | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/scorers/json-schema.ts b/src/scorers/json-schema.ts index c299302..9663a4f 100644 --- a/src/scorers/json-schema.ts +++ b/src/scorers/json-schema.ts @@ -56,8 +56,15 @@ export function validate(value: unknown, schema: JsonSchema, path = "$"): string errors.push(`${path}: shorter than minLength ${schema.minLength}`); if (schema.maxLength !== undefined && value.length > schema.maxLength) errors.push(`${path}: longer than maxLength ${schema.maxLength}`); - if (schema.pattern && !new RegExp(schema.pattern).test(value)) - errors.push(`${path}: does not match pattern ${schema.pattern}`); + if (schema.pattern) { + try { + if (!new RegExp(schema.pattern).test(value)) + errors.push(`${path}: does not match pattern ${schema.pattern}`); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + errors.push(`${path}: invalid pattern ${schema.pattern}: ${message}`); + } + } } if (isPlainObject(value)) { diff --git a/tests/scorers.test.ts b/tests/scorers.test.ts index b53c6a2..9049099 100644 --- a/tests/scorers.test.ts +++ b/tests/scorers.test.ts @@ -107,6 +107,29 @@ describe("json-schema", () => { ); expect(errs.length).toBe(2); }); + it("returns a path-attributed failure for an invalid nested pattern", async () => { + const r = await run( + jsonSchemaScorer, + { + type: "json-schema", + schema: { + type: "object", + properties: { account: { type: "string", pattern: "[0-9" } }, + }, + }, + ctx('{"account":"123"}'), + ); + + expect(r.passed).toBe(false); + expect(r.score).toBe(0); + expect(r.reason).toContain("$.account: invalid pattern [0-9"); + expect(r.reason).toMatch(/unterminated/i); + }); + it("still reports a normal mismatch for a valid pattern", () => { + expect(validate("abc", { type: "string", pattern: "^\\d+$" })).toEqual([ + "$: does not match pattern ^\\d+$", + ]); + }); }); describe("embedding-similarity", () => {