What Model are you using?
Describe the bug
CitationMixin._get_span (instructor/v2/dsl/citation.py) interpolates the LLM-generated quote directly into a regex fuzzy-match pattern without escaping it:
minor = quote
s = regex.search(f"({minor}){{e<={errs_}}}", major)
Because quote comes straight from the model's substring_quotes, any regex metacharacter it contains — unbalanced parentheses/brackets, *, +, ?, \, etc., all common in ordinary prose — is treated as part of the pattern. This raises regex.error (crashing validation) or silently matches the wrong span, instead of the documented behavior of finding the span or dropping the quote.
To Reproduce
from instructor import CitationMixin
class Answer(CitationMixin):
pass
context = "The margin is 50% (approx) this quarter."
# A quote with an unbalanced parenthesis, as an LLM might return:
Answer.model_validate(
{"substring_quotes": ["50% (approx"]},
context={"context": context},
)
Result:
regex.error: missing ) at position 19
Expected behavior
The span should be resolved (the quote normalized back to the matching substring of the context), or, if it does not match, the quote should be dropped from substring_quotes — never a regex.error. Fuzzy (edit-distance) matching should keep working.
The fix is to escape the quote with regex.escape() before building the pattern. Proposed in #2430.
What Model are you using?
CitationMixinvalidation, independent of the model)Describe the bug
CitationMixin._get_span(instructor/v2/dsl/citation.py) interpolates the LLM-generated quote directly into aregexfuzzy-match pattern without escaping it:Because
quotecomes straight from the model'ssubstring_quotes, any regex metacharacter it contains — unbalanced parentheses/brackets,*,+,?,\, etc., all common in ordinary prose — is treated as part of the pattern. This raisesregex.error(crashing validation) or silently matches the wrong span, instead of the documented behavior of finding the span or dropping the quote.To Reproduce
Result:
Expected behavior
The span should be resolved (the quote normalized back to the matching substring of the context), or, if it does not match, the quote should be dropped from
substring_quotes— never aregex.error. Fuzzy (edit-distance) matching should keep working.The fix is to escape the quote with
regex.escape()before building the pattern. Proposed in #2430.