fix(get_contract_list): reject non-string metadataFilters values; clarify operator key format#65
Open
sd-gh-bot wants to merge 1 commit into
Open
fix(get_contract_list): reject non-string metadataFilters values; clarify operator key format#65sd-gh-bot wants to merge 1 commit into
sd-gh-bot wants to merge 1 commit into
Conversation
…clarify operator key format
The LLM incorrectly sent metadataFilters as {"48802": {"\": "NOT_SET"}} (operator
in value) instead of {"48802[\]": "NOT_SET"} (operator in key). The serialization
code cast the object value to string via URLSearchParams.append() which produced
"[object Object]", causing the Django backend to receive an unparseable currency value
and throw ValueError -> 500.
Changes:
- Add ValidationError for non-string metadataFilters values with a message that
directs the LLM to use bracket notation in the key ("48802[\]")
- Update tool description to document the key format and per-type value format
explicitly with examples matching the Django filter_processor spec
- Update inputSchema.metadataFilters.description with concise format reminder
- Add two new tests: object-value rejection and correct string serialisation
Sentry event: 7e020f86dcfa4dc194efd7e46a9e164a (prod-usa, 2026-05-12T15:00:17Z)
LangSmith trace: 019e1cb3-bda0-72d1-8d08-14a64c16591f
Co-authored-by: Achuth Karakkat <achuth@spotdraft.com>
Comment on lines
231
to
240
| metadataFilters: { | ||
| type: 'object', | ||
| description: 'Filters to apply to metadata fields. Available operators depend on the field data type.', | ||
| description: | ||
| 'Filters for metadata (key pointer) fields. ' + | ||
| 'Key format: "<key_pointer_id>[$operator]" (bracket notation, e.g. "48802[$ne]"). ' + | ||
| 'For $eq the operator is optional. ' + | ||
| 'Values must be plain strings — never pass objects. ' + | ||
| 'CURRENCY values: "<CODE> <amount>" e.g. "USD 1000". ' + | ||
| 'DATE values: ISO 8601 e.g. "2025-06-07T00:00:00Z".', | ||
| }, |
There was a problem hiding this comment.
metadataFilters is defined in the tool’s inputSchema but still allows the TypeScript shape implied by a loose object typing, while the implementation now rejects any non-string value at runtime (added in the same file around the metadataFilters validation loop). This creates a public contract mismatch: TS callers can compile object-operator formats like { '48802': { $ne: 'NOT_SET' } }, but the call will throw ValidationError instead. Consider tightening the schema/typing to enforce Record<string, string> (and aligning it with the tool schema). (Original place noted by the system: lines 257-263.)
Finding type: Breaking Changes | Severity: 🟢 Low
Want Baz to fix this for you? Activate Fixer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User description
Problem
LLM called
get_contract_listwith metadataFilters using operator-in-value format:{"metadataFilters": {"48802": {"$ne": "NOT_SET"}, "52421": {"$ne": "NOT_SET"}}}The serialisation code cast the object value to a string via URLSearchParams.append, which produces
[object Object]. Django receivedfilter_metadata__48802=[object Object], tried to parse it as a currency value, attemptedint('Object]')→ ValueError → HTTP 500.Sentry event: 7e020f86dcfa4dc194efd7e46a9e164a (env: prod-usa, 2026-05-12T15:00:17Z)
LangSmith trace: 019e1cb3-bda0-72d1-8d08-14a64c16591f
User: FullStory workspace, query about Macy's ARR
Root cause
The metadataFilters tool description showed allowed operators but never showed how to include the operator in the key. The LLM inferred the wrong format.
Correct format (matching Django filter_processor spec):
{"48802[$ne]": "NOT_SET", "52421[$gt]": "USD 1000000"}Changes
Generated description
Below is a concise technical summary of the changes proposed in this PR:
Clarify metadata filters instructions in the
get_contract_listtool so operators are embedded via bracket notation, value formats per type are spelled out, and the schema notes that values must be plain strings. Add validation insidegetContractListto reject non-string metadata filters and expand tests to cover both rejection and proper serialization.getContractList, throw aValidationErrorwhen values are not strings, and cover rejection plus correct serialization through tests.Modified files (2)
Latest Contributors(2)
Modified files (1)
Latest Contributors(2)